Haskell:用文件夹定义产品



我试图用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

在您的情况下,fnew_product, xxs。当您使用无点样式时,Haskell会尝试推断new_product的单态签名,但会失败,因为它无法确定选择哪个Foldable实例(基于foldr)。另一方面,当您包含xs时,Haskell不再被绑定到推断单态签名,因此一切都可以工作。

这种疯狂是有原因的:关键是当你写像f = ...这样的东西时,很自然地假设f只被求值一次。然而,除非我们强制f是单态的,否则情况不一定是这样的。

用一个与你的函数相关的例子:假设我推断p = num_product [1..1000]的类型是Num a => a(在这种情况下最通用的类型),那么使用p :: Intp :: Integer将导致我们至少计算p两次。

Haskell因此决定不泛化顶级绑定:您只推断具有显式变量的函数的多态签名(即。在等号的左边)。也就是说,如果您希望显式地编写多态类型签名,您可以自由地这样做。

最新更新