如何指定从中调用函数的实例

时间:2016-05-31 12:01:20

标签: haskell

假设我有一个类型类,对于这个类型类的每个实例,我都有一个函数

f :: [Bool] -> Maybe (a, [a])

我怎么称呼f?更确切地说,如果b是此类型类中的另一种类型,我如何指定我的意思是来自a的实例的f而不是b的实例?

3 个答案:

答案 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有两个独特的实例。当aInt时,其中一个被提取,另一个被提取时为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"可以同时生成IntBool。这本质上是模棱两可的,因为上面的程序可以打印“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

这是因为&&需要Boollength返回Int+强制两个参数具有相同的类型(所以{{1} }}也必须是f "testing"

还在工作

Int