Haskell:使用foldr定义产品

时间:2016-08-25 05:00:10

标签: haskell

我正在尝试使用product定义foldr

我可以用:

new_product xs = foldr (*) 1 xs

但不是:

new_product = foldr (*) 1

或:

new_product = \xs -> foldr (*) 1 xs

两个定义都产生相同的错误:

  

使用'folder'

时没有(可折叠的t0)的实例      

类型变量't0'是不明确的

     

相关绑定包括

     

new_product :: t0整数 - >整数

是某种类型错误吗?

我该如何解决?

1 个答案:

答案 0 :(得分:3)

这是Monomorphism restriction正在发挥作用。解决方案是添加类型签名:

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_productxxs。当您具有无点样式时,Haskell会尝试推断new_product的单形签名并失败,因为它无法确定要选择哪个Foldable实例(基于foldr)。另一方面,当你包含xs时,Haskell不再需要推断单态签名,因此一切正常。

这种疯狂是有道理的:关键是当你写f = ...之类的东西时,很自然地认为f只被评估过一次。然而,除非我们强迫f变为单态,否则情况不一定如此。

使用与您的函数相关的示例:假设我推断p = num_product [1..1000]具有类型Num a => a(在这种情况下是最常见的类型),然后使用p :: Int和{{1将导致我们评估p :: Integer至少两次。

因此,Haskell决定不概括顶级绑定:你只推断出其变量显式的函数的多态签名(即在等号的左侧)。也就是说,如果你想明确地写一个多态类型签名,你可以自由地这样做。