[英]Why doesn't f=(+) need a type annotation?
我的意思是,例如,
f :: (Enum a) => a -> a --without this line, there would be an error
f = succ
这是因为succ
需要它的参数是可枚举的( succ :: (Enum a) => a -> a
)
但对于(+)
f = (+) --ok
虽然(+)
的声明是(+) :: (Num a) => a –> a –> a
。
我的意思是,为什么我不需要声明f
为f :: (Num a) => a –> a –> a
?
因为违约。 Num
是一个'defaultable'类型类,这意味着如果你让它不受约束,编译器会做一些关于你打算用它的类型的智能猜测。 尝试将该定义放在模块中,然后运行
:t f
在ghci
; 它应告诉你(IIRC) f :: Integer -> Integer -> Integer
。 编译器不知道哪a
你想使用,所以猜测Integer
; 从那以后,它就是那个猜测。
为什么不推断f
的多态类型? 由于可怕的[1]单态性限制。 当编译器看到
f = (+)
它认为' f
是一个值',这意味着它需要一个单一的(单态)类型。 Eta-将定义扩展为
f x = (+) x
你会得到多态类型
f :: Num a => a -> a -> a
同样,如果你扩展你的第一个定义
f x = succ x
你不再需要类型签名了。
[1] GHC文档中的实际名称!
我的意思是,为什么我不需要声明
f
为(+) :: (Num a) => a –> a –> a
?
如果你声明f
的签名,你需要这样做。 但是如果你不这样做,编译器就会“猜测”签名本身 - 在这种情况下,这并不是非常值得注意的,因为它基本上只能复制和粘贴(+)
的签名。 这正是它将要做的。
......或者至少它应该做什么。 如果你有-XNoMonomorphism
标志,它确实-XNoMonomorphism
。 否则, 可怕的是 , 可怕的单态限制步入 ,因为f
的定义是形状ConstantApplicativeForm = Value ; 这使得编译器将签名变为可以找到的下一个最佳非多态类型,即Integer -> Integer -> Integer
。 为了防止这种情况,您应该为所有顶级功能手动提供正确的签名。 这也可以防止很多混乱,并且许多错误变得不那么混乱。
单态限制是原因
f = succ
不会单独工作:因为它也具有这种CAF形状,编译器不会尝试推断正确的多态类型,而是尝试找到一些具体的实例来制作单态签名。 但与Num
不同, Enum
类不提供默认实例。
可能的解决方案,按优先顺序排
-XNoMonomorphismRestriction
。 fa = succ a
, fab = a+b
的形式编写函数定义。 因为有明确提到的参数,这些参数不符合CAF的条件,因此单态性限制不会起作用。 Haskell默认Num
约束为Int
或Integer
,我忘了哪个。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.