sqd*_*sqd 10 haskell functional-programming
我的意思是,例如,
f :: (Enum a) => a -> a --without this line, there would be an error
f = succ
Run Code Online (Sandbox Code Playgroud)
这是因为succ
需要它的参数是可枚举的(succ :: (Enum a) => a -> a
)
但对于 (+)
f = (+) --ok
Run Code Online (Sandbox Code Playgroud)
虽然(+)
声明是(+) :: (Num a) => a –> a –> a
.
我的意思是,我为什么不需要申报f
的f :: (Num a) => a –> a –> a
?
Jon*_*ast 14
因为违约. Num
是一个'defaultable'类型类,这意味着如果你让它不受约束,编译器会做出一些关于你打算用它的类型的智能猜测.尝试将该定义放在模块中,然后运行
:t f
Run Code Online (Sandbox Code Playgroud)
in ghci
; 它应该告诉你(IIRC)f :: Integer -> Integer -> Integer
.编译器不知道a
你想使用哪个,所以它猜对了Integer
; 从那以后,它就是那个猜测.
为什么不推断出多态类型f
?由于可怕的[1]单态性限制.当编译器看到
f = (+)
Run Code Online (Sandbox Code Playgroud)
它认为' f
是一个价值',这意味着它需要一个单一的(单态)类型.Eta-将定义扩展为
f x = (+) x
Run Code Online (Sandbox Code Playgroud)
你会得到多态类型
f :: Num a => a -> a -> a
Run Code Online (Sandbox Code Playgroud)
同样,如果你扩展你的第一个定义
f x = succ x
Run Code Online (Sandbox Code Playgroud)
你不再需要类型签名了.
[1] GHC文档中的实际名称!
我的意思是,我为什么不需要申报
f
的(+) :: (Num a) => a –> a –> a
?
如果你声明签名,你需要这样做f
.但是,如果你不这样做,编译器将"猜测"签名本身 - 在这种情况下,这并非显着,因为它基本上只能复制和粘贴签名(+)
.这正是它将要做的.
......或者至少它应该做什么.如果你有-XNoMonomorphism
旗帜,它确实如此.否则,好的,可怕的单态限制步骤因为f
's的定义是形状ConstantApplicativeForm = Value ; 这使得编译器将签名愚蠢到它能找到的下一个最好的非多态类型,即Integer -> Integer -> Integer
.为了防止这种情况,您应该为所有顶级功能手动提供正确的签名.这也可以防止很多混乱,许多错误变得不那么混乱.
单态限制是原因
f = succ
Run Code Online (Sandbox Code Playgroud)
不会单独工作:因为它也具有这种CAF形状,编译器不会尝试推断正确的多态类型,而是尝试找到一些具体的实例来制作单态签名.但不像Num
,Enum
该类不提供默认实例.
可能的解决方案,按优先顺序排
-XNoMonomorphismRestriction
.f a = succ a
,f a b = a+b
.因为有明确提到的参数,这些参数不符合CAF的条件,因此单态性限制不会起作用. 归档时间: |
|
查看次数: |
346 次 |
最近记录: |