2011-12-15 89 views
11

当使用交互式GHC解释,有可能要求推断类型的表达式:GHCi如何为类型变量选择名称?

Prelude> :t map 
map :: (a -> b) -> [a] -> [b] 

看来,它需要的类型变量的名称从签名,因为mapdefined作为

map :: (a -> b) -> [a] -> [b] 
map _ []  = [] 
map f (x:xs) = f x : map f xs 

在Prelude中。这很有道理!我的问题是:在没有给定签名时如何选择类型变量名称?

一个例子是

Prelude> :t map fst 
map fst :: [(b, b1)] -> [b] 

它捡起名bb1。很明显,重命名必须发生,而只是开始ab,......将给予

map fst :: [(a, b)] -> [a] 

代替,我觉得稍微更具可读性。

回答

13

据我所知,ghci选择名称的顺序与它推断的类型相同。它使用您提到的命名方案来决定结果的类型名称,即[b],因为这是在map的定义中指定的类型名称。然后它决定作为map的第一个参数的函数也应该返回b类型的东西。

因此,要命名的其余类型变量是参数元组中的第二个元素的类型变量,其值为fst,同样,它查看fst的定义以决定使用哪个名称。 fst :: (a, b) -> a的定义,因此b将是此处的首选名称,但由于b已被占用,因此它会附加1,以便它变为b1

我认为这个系统在你不处理任意类型的情况下具有优势,就像这里的情况一样。如果得到的类型看起来是这样的,例如:

castAdd :: (Num n, Num n1, Num n2) => n -> n1 -> n2 

...这可以说是比更具可读性:

castAdd :: (Num a, Num b, Num c) => a -> b -> c 

...因为你可以主要依赖于n#表示一个数字类型,因为Num的类定义是class Num n where ...

编辑:是的,我知道castAdd是不可能实现的,但它只是一个类型的例子。

+1

谢谢,这是一个很好的解释!我没有想到你想要重新命名几个`n`但保持相关的情况。 – 2011-12-15 14:26:06