简体   繁体   English

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

[英]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 ? 我的意思是,为什么我不需要声明ff :: (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: 可能的解决方案,按优先顺序排

  1. Always add signatures. 始终添加签名。 You really should. 你真的应该。
  2. Enable -XNoMonomorphismRestriction . 启用-XNoMonomorphismRestriction
  3. Write your function definitions in the form fa = succ a , fab = a+b . fa = succ afab = 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约束为IntInteger ,我忘了哪个。

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

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