Haskell:使用foldr定义产品

Haskell:使用foldr定义产品,haskell,Haskell,我试图用foldr定义产品: 我可以用: 新产品xs=foldr(*)1 xs 但不是: new_product=foldr(*)1 或: 新产品=\xs->foldr(*)1 xs 两个定义产生相同的错误: 没有因使用“文件夹”而产生的(可折叠t0)实例 类型变量“t0”不明确 相关绑定包括 新产品::t0整数->整数 这是某种类型的类型错误吗 我怎样才能修好它呢?这是工作中的问题。解决方案是添加类型签名: new_product :: (Foldable t, Num b) => t

我试图用
foldr
定义
产品

我可以用:

新产品xs=foldr(*)1 xs

但不是:

new_product=foldr(*)1

或:

新产品=\xs->foldr(*)1 xs

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

没有因使用“文件夹”而产生的(可折叠t0)实例

类型变量“t0”不明确

相关绑定包括

新产品::t0整数->整数

这是某种类型的类型错误吗

我怎样才能修好它呢?

这是工作中的问题。解决方案是添加类型签名:

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
新产品
x
xs
。当您使用无点样式时,Haskell尝试为
新产品
推断单态签名,但失败了,因为它无法确定要选择哪个
可折叠
实例(基于
foldr
)。另一方面,当您包含
xs
时,Haskell不再必须推断单态签名,因此一切都是有效的

这种疯狂是有原因的:关键是当你编写类似于
f=…
的东西时,很自然地会假设
f
只被计算一次。然而,除非我们强迫
f
为单态,否则情况未必如此

使用与函数相关的示例:假设我推断
p=num_product[1..1000]
具有类型
num a=>a
(本例中最常用的类型),那么使用
p::Int
p::Integer
将导致我们至少计算
p


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

但是我没有在第一个定义中指定类型。如果需要类型签名,为什么它会起作用?也许值得一提的是,如果您希望使用
NoMonomorphismRestriction
语言pragma,您可以关闭单态限制;它不影响
let
绑定。单态限制实际上很少有用,如果您在编译代码时启用了优化,它就不太可能有用;如果你感到困惑,就把它关掉。所谓“这个问题已经由‘什么是单态限制’来回答了?”的说法是完全错误的,对用户来说是有辱人格的。