我已经定义了类似于一个类型的类型类,其中包含我的程序所需的一系列函数.遗憾的是,它需要多种多态类型,但并非这种多参数类型类的每个函数都需要每种类型.GHC困扰我不可挽救的类型,我无法运行代码.
一个简化的例子:
{-# LANGUAGE MultiParamTypeClasses #-}
class Foo a b where
-- ...
bar :: a -> ()
baz :: Foo a b => a -> ()
baz = bar
Run Code Online (Sandbox Code Playgroud)
GHC说
Possible fix: add a type signature that fixes these type variable(s)
Run Code Online (Sandbox Code Playgroud)
我怎么能这样做b?特别是当我想保持b多态时.只有一个实例Foo应该定义这种类型.
Car*_*arl 12
这是不可能的.
根本问题是多参数类型类依赖于每个类型参数.如果类中的特定定义不使用每个类型参数,编译器将永远无法知道您的意思是什么实例,并且您甚至无法指定它.请考虑以下示例:
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
Run Code Online (Sandbox Code Playgroud)
这两个实例的参数完全不同.编译器必须选择其中一个实例的唯一方法是匹配两个类型参数.但是没有办法指定类型参数是什么.这课很简单.没有办法调用该bar函数,因为您永远无法为编译器提供足够的信息来解析要使用的类实例.
那么为什么类定义不会被编译器拒绝呢?因为你有时可以通过FunctionalDependencies扩展来使它工作.
如果一个类有多个参数,但它们是相关的,那么这些信息有时会以允许类成员不使用类定义中的每个类型变量的方式添加到类的定义中.
class Foo a b | a -> b where
bar :: String -> IO a
Run Code Online (Sandbox Code Playgroud)
使用该定义(需要FunctionalDependencies扩展名),您告诉编译器,对于任何特定选择a,只有一个有效选择b.尝试甚至定义上述两个实例都是编译错误.
鉴于此,编译器知道它可以Foo仅根据类型选择要使用的实例a.在那种情况下,bar可以调用.