如何处理多参数类型类的函数,谁不需要每种类型的类型类? [英] How to handle functions of a multi-parameter typeclass, who not need every type of the typeclass?

查看:133
本文介绍了如何处理多参数类型类的函数,谁不需要每种类型的类型类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我定义了一个类型类似于一个接口的函数,这个函数需要一些我的程序所需的函数。可悲的是,它需要多个多态类型,但并不是每个类型都需要这个多参数类型类的每个函数。 GHC困扰着我不可或缺的类型,我无法获得代码运行。

I've defined a typeclass similar to an interface with a bunch of functions required for my program. Sadly, it needs multiple polymorphic types, but not every function of this multi-parameter typeclass needs every type. GHC haunts me with undeduceable types and i can't get the code running.

一个简化的例子:

A reduced example:

{-# LANGUAGE MultiParamTypeClasses #-}

class Foo a b where
    -- ...
    bar :: a -> ()

baz :: Foo a b => a -> ()
baz = bar

GHC表示

GHC says

Possible fix: add a type signature that fixes these type variable(s)

如何为 b 执行此操作?特别是当我想保持 b 多态时。只有 Foo 的实例应该定义这种类型。

How can I do this for b? Especially when I want to keep b polymorphic. Only an instance of Foo should define what this type is.

推荐答案

这是不可能的。

底层的问题是多参数类型的类依赖于每个类型的参数。如果类中的特定定义不使用每个类型参数,那么编译器将永远无法知道您的意思是什么,甚至永远无法指定它。考虑下面的例子:

The underlying problem is that a multiparameter type class depends on every type parameter. If a particular definition in the class doesn't use every type parameter, the compiler will never be able to know what instance you mean, and you'll never even be able to specify it. Consider the following example:

class Foo a b where
    bar :: String -> IO a

instance Foo Int Char where
    bar x = return $ read x

instance Foo Int () where
    bar x = read <$> readFile x

这两个实例的参数完全不同。编译器必须选择其中一个实例的唯一方法是匹配两个类型参数。但是没有办法指定类型参数。这堂课只是简单的破碎。无法调用 bar 函数,因为您永远无法为编译器提供足够的信息来解析要使用的类实例。

Those two instances do entirely different things with their parameter. The only way the compiler has to select one of those instances is matching both type parameters. But there's no way to specify what the type parameter is. The class is just plain broken. There's no way to ever call the bar function, because you can never provide enough information for the compiler to resolve the class instance to use.

那么为什么类定义没有被编译器拒绝呢?因为有时你可以使用 FunctionalDependencies 扩展名来工作。

So why is the class definition not rejected by the compiler? Because you can sometimes make it work, with the FunctionalDependencies extension.

如果一个类有多个参数,但它们相关的信息有时可以添加到类的定义中,使得类成员不能在类的定义中使用每个类型变量。

If a class has multiple parameters, but they're related, that information can sometimes be added to the definition of the class in a way that allows a class member to not use every type variable in the class's definition.

class Foo a b | a -> b where
    bar :: String -> IO a

使用该定义(需要 FunctionalDependencies 扩展名),您告诉编译器,对于 a 的任何特定选择,只有一个有效选择 b 。试图甚至定义上述两个实例都是一个编译错误。

With that definition (which requires the FunctionalDependencies extension), you are telling the compiler that for any particular choice of a, there is only one valid choice of b. Attempting to even define both of the above instances would be a compile error.

鉴于此,编译器知道它可以选择 Foo的实例仅基于类型 a 使用。在这种情况下,可以调用 bar

Given that, the compiler knows that it can select the instance of Foo to use based only on the type a. In that case, bar can be called.

这篇关于如何处理多参数类型类的函数,谁不需要每种类型的类型类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆