如果没有类型声明的定义将引发错误:
f :: Eq t => (t,t) -> Bool -- omiting this line will result in an error
f = \(x,y) -> x==y
(我知道这个函数可以写得更短,但这不是重点。)
另一方面,在使用map
的函数中使用相同的 lambda函数可以正常工作而不会产生错误:
g l = map (\(x,y) -> x==y) l
(正如图示:g [(3,4),(5,5),(7,6)]
将产生[False,True,False]
此外,代码完全正常,它似乎与上面的原始f
完全相同。这里的类型推断似乎有效。
f' (x,y) = x==y
所以我的问题是:为什么我们需要第一种情况下的类型声明,而不是第二种情况和第三种情况?
答案 0 :(得分:4)
如果您使用:
{-# LANGUAGE NoMonomorphismRestriction #-}
f = \(x,y) -> x==y
你没有收到错误。
<强>更新强>
关于单同性限制的Haskell Wiki页面(link)提供了为什么这些定义被区别对待的一些细节:
f1 x = show x
f2 = \x -> show x
第一个版本和第二个版本之间的区别在于第一个版本通过&#34;函数绑定&#34;来绑定x。 (参见Haskell 2010报告的4.4.3节),因此不受限制,但第二个版本没有。一个被允许而另一个被允许的原因是,它被认为是明确的,共享f1将不会共享任何计算,并且不太清楚共享f2将具有相同的效果。如果这似乎是任意的,那是因为它是。很难设计出一种不允许主观意外行为的客观规则。即使他们做了相当合理的事情,有些人也会违反规则。
答案 1 :(得分:2)
正如@ErikR在评论中所说,这是由Monomorphism restriction引起的。我们在错误消息中也看到了这一点:
因使用'=='而产生(Eq a0)的实例 类型变量'a0'是不明确的 可能原因:单态限制适用于以下内容:
f ::(a0,a0) - &gt;布尔
(以......为准) 注意:有几种可能的情况:
实例Eq a =&gt; Eq(GHC.Real.Ratio a) - 定义于'GHC.Real'
实例Eq() - 在'GHC.Classes'中定义 instane(Eq a,Eq b)=&gt; Eq(a,b) - 在'GHC.Classes'中定义 ..plus 22 others
单同性限制意味着编译器尝试将模糊类型实例化为非模糊类型。 (资料来源:What is the monomorphism restriction?)。
所以,Haskell想要放一个实例,但它不能 - 它找到几个,并且不知道选择哪个。
这解释了为什么添加类型可以解决问题:现在编译器知道要选择什么。
“单态限制”是Haskell类型推断中的反直觉规则。如果您忘记提供类型签名,有时此规则将使用“类型默认”规则填充具有特定类型的自由类型变量。