假设我有一个类型类,对于这个类型类的每个实例,我都有一个函数
f :: [Bool] -> Maybe (a, [a])
我怎么称呼f?更确切地说,如果b是此类型类中的另一种类型,我如何指定我的意思是来自a的实例的f而不是b的实例?
答案 0 :(得分:7)
有时您必须添加类型注释。考虑类型类Read
:
class Read a where
read :: String -> a
如果您尝试read "1"
期望获得整数1
,则会收到错误,因为无法知道类型a
是什么。但是,这有效:read "1" :: Int
。
如果您在编译器可以找出f
是什么的情况下使用函数a
,那么它将正常工作。否则,您必须通过添加适当的类型注释来帮助编译器。
答案 1 :(得分:3)
类型类实例由声明它们的特定类型索引。例如,在以下情况中:
class YourClass a where
f :: [Bool] -> Maybe (a, [a])
instance YourClass Int where
f = error "Define me"
instance YourClass Char where
f = error "Define me"
YourClass
有两个独特的实例。当a
为Int
时,其中一个被提取,另一个被提取时为Char
。使用f
函数实际应用的类型自动解析实例。
因此,每当您使用f
时,就好像它具有特定签名[Bool] -> Maybe (Int, [Int])
一样,Int
的实例会自动被选中。由于Haskell还具有令人难以置信的强大类型推断,因此在大多数情况下并不需要指定此特定签名,并且编译器会再次自动地从上下文中解析它。
基本上,你可以在你拥有实例的所有类型上使用该函数,并安全地期望编译器为你完成其余的工作。
答案 2 :(得分:3)
为了补充其他答案,我会指出确实有些案例可能含糊不清。
例如:
class C a where
f :: String -> a
instance C Int where
f s = length s
instance C Bool where
f s = s == "hello!"
main :: IO ()
main = print (f "testing")
现在,print
接受任何(Show
能)类型,而f "testing"
可以同时生成Int
和Bool
。这本质上是模棱两可的,因为上面的程序可以打印“False”以及“7”。编译器无法解决这个问题。
作为解决方案,我们可以使用
main = print (f "testing" :: Int)
-- or
main = print (f "testing" :: Bool)
消除歧义。另一个不太方便的选择是
main = print ((f :: String -> Int) "testing")
或甚至在GHC 8.0中,正确的扩展名,
main = print (f @ Int "testing") -- explicit choice for type a
但请注意,在某些情况下,没有歧义,GHC可以创造奇迹。例如:
main = print (f "testing" && True) -- Bool is chosen here
main = print (f "testing" + length [1,2]) -- Int is chosen here
这是因为&&
需要Bool
,length
返回Int
而+
强制两个参数具有相同的类型(所以{{1} }}也必须是f "testing"
。
还在工作
Int