我试图用foldr
定义product
:
我可以这样做:
new_product xs = foldr (*) 1 xs
但不是:
new_product = foldr (*) 1
或:
new_product = xs -> foldr (*) 1 xs
两个定义产生相同的错误:
由于使用' folder '而产生的(Foldable t0)没有实例
类型变量' t0 '有二义性
相关绑定包括
new_product:: t0 Integer -> Integer
是某种类型的输入错误吗?
我该如何修复它?
这就是起作用的单态限制。解决方案是添加一个类型签名:
new_product :: (Foldable t, Num b) => t b -> b
new_product = foldr (*) 1
本质上,这里的问题是,除非你在GHCi(这是禁用的)Haskell拒绝推断一个多态类型签名,除非你显式地有函数的变量。作为一个具体的例子:
f x = ... -- `f` can infer polymorphic type (in `x`)
f = x -> ... -- `f` infers a monomorphic type
在您的情况下,f
是new_product
, x
是xs
。当您使用无点样式时,Haskell会尝试推断new_product
的单态签名,但会失败,因为它无法确定选择哪个Foldable
实例(基于foldr
)。另一方面,当您包含xs
时,Haskell不再被绑定到推断单态签名,因此一切都可以工作。
这种疯狂是有原因的:关键是当你写像f = ...
这样的东西时,很自然地假设f
只被求值一次。然而,除非我们强制f
是单态的,否则情况不一定是这样的。
用一个与你的函数相关的例子:假设我推断p = num_product [1..1000]
的类型是Num a => a
(在这种情况下最通用的类型),那么使用p :: Int
和p :: Integer
将导致我们至少计算p
两次。
Haskell因此决定不泛化顶级绑定:您只推断具有显式变量的函数的多态签名(即。在等号的左边)。也就是说,如果您希望显式地编写多态类型签名,您可以自由地这样做。