繁体   English   中英

为什么f =(+)不需要类型注释?

[英]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

我的意思是,为什么我不需要声明ff :: (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类不提供默认实例。

可能的解决方案,按优先顺序排

  1. 始终添加签名。 你真的应该。
  2. 启用-XNoMonomorphismRestriction
  3. fa = succ afab = a+b的形式编写函数定义。 因为有明确提到的参数,这些参数不符合CAF的条件,因此单态性限制不会起作用。

Haskell默认Num约束为IntInteger ,我忘了哪个。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM