[英]Why doesn't f=(+) need a type annotation?
I mean, for example, 我的意思是,例如,
f :: (Enum a) => a -> a --without this line, there would be an error
f = succ
It's because succ
needs its parameter to be enumerable ( succ :: (Enum a) => a -> a
) 这是因为succ
需要它的参数是可枚举的( succ :: (Enum a) => a -> a
)
but for (+)
但对于(+)
f = (+) --ok
Though (+)
's declaration is (+) :: (Num a) => a –> a –> a
. 虽然(+)
的声明是(+) :: (Num a) => a –> a –> a
。
I mean, why don't I need to declare f
as f :: (Num a) => a –> a –> a
? 我的意思是,为什么我不需要声明f
为f :: (Num a) => a –> a –> a
?
Because of defaulting. 因为违约。 Num
is a 'defaultable' type class, meaning that if you leave it un-constrained, the compiler will make a few intelligent guesses as to which type you meant to use it as. Num
是一个'defaultable'类型类,这意味着如果你让它不受约束,编译器会做一些关于你打算用它的类型的智能猜测。 Try putting that definition in a module, then running 尝试将该定义放在模块中,然后运行
:t f
in ghci
; 在ghci
; it should tell you (IIRC) f :: Integer -> Integer -> Integer
. 它应告诉你(IIRC) f :: Integer -> Integer -> Integer
。 The compiler didn't know which a
you wanted to use, so it guessed Integer
; 编译器不知道哪a
你想使用,所以猜测Integer
; and since that worked, it went with that guess. 从那以后,它就是那个猜测。
Why didn't it infer a polymorphic type for f
? 为什么不推断f
的多态类型? Because of the dreaded[1] monomorphism restriction. 由于可怕的[1]单态性限制。 When the compiler sees 当编译器看到
f = (+)
it thinks ' f
is a value', which means it needs a single (monomorphic) type. 它认为' f
是一个值',这意味着它需要一个单一的(单态)类型。 Eta-expand the definition to Eta-将定义扩展为
f x = (+) x
and you will get the polymorphic type 你会得到多态类型
f :: Num a => a -> a -> a
and similarly if you eta-expand your first definition 同样,如果你扩展你的第一个定义
f x = succ x
you don't need a type signature any more. 你不再需要类型签名了。
[1] Actual name from the GHC documentation! [1] GHC文档中的实际名称!
I mean, why don't I need to declare
f
as(+) :: (Num a) => a –> a –> a
? 我的意思是,为什么我不需要声明f
为(+) :: (Num a) => a –> a –> a
?
You do need to do that, if you declare the signature of f
at all. 如果你声明f
的签名,你需要这样做。 But if you don't, the compiler will “guess” the signature itself – in this case this isn't all to remarkable since it can basically just copy&paste the signature of (+)
. 但是如果你不这样做,编译器就会“猜测”签名本身 - 在这种情况下,这并不是非常值得注意的,因为它基本上只能复制和粘贴(+)
的签名。 And that's precisely what it will do. 这正是它将要做的。
...or at least what it should do. ......或者至少它应该做什么。 It does, provided you have the -XNoMonomorphism
flag on. 如果你有-XNoMonomorphism
标志,它确实-XNoMonomorphism
。 Otherwise, well, the dreaded monomorphism restriction steps in because f
's definition is of the shape ConstantApplicativeForm = Value ; 否则, 可怕的是 , 可怕的单态限制步入 ,因为f
的定义是形状ConstantApplicativeForm = Value ; that makes the compiler dumb down the signature to the next best non-polymorphic type it can find, namely Integer -> Integer -> Integer
. 这使得编译器将签名变为可以找到的下一个最佳非多态类型,即Integer -> Integer -> Integer
。 To prevent this, you should in fact supply the right signature by hand, for all top-level functions. 为了防止这种情况,您应该为所有顶级功能手动提供正确的签名。 That also prevents a lot of confusion, and many errors become way less confusing. 这也可以防止很多混乱,并且许多错误变得不那么混乱。
The monomorphism restriction is the reason 单态限制是原因
f = succ
won't work on its own: because it also has this CAF shape, the compiler does not try to infer the correct polymorphic type, but tries to find some concrete instantiation to make a monomorphic signature. 不会单独工作:因为它也具有这种CAF形状,编译器不会尝试推断正确的多态类型,而是尝试找到一些具体的实例来制作单态签名。 But unlike Num
, the Enum
class does not offer a default instance. 但与Num
不同, Enum
类不提供默认实例。
Possible solutions, ordered by preference: 可能的解决方案,按优先顺序排
-XNoMonomorphismRestriction
. 启用-XNoMonomorphismRestriction
。 fa = succ a
, fab = a+b
. 以fa = succ a
, fab = a+b
的形式编写函数定义。 Because there are explicitly mentioned arguments, these don't qualify as CAF, so the monomorphism restriction won't kick in. 因为有明确提到的参数,这些参数不符合CAF的条件,因此单态性限制不会起作用。 Haskell默认Num
约束为Int
或Integer
,我忘了哪个。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.