lambda函数的Haskell类型推断(在地图中)

时间:2016-05-11 17:25:32

标签: haskell lambda type-inference

示例1

如果没有类型声明的定义将引发错误:

f :: Eq t => (t,t) -> Bool  -- omiting this line will result in an error
f = \(x,y) -> x==y

(我知道这个函数可以写得更短,但这不是重点。)

示例2

另一方面,在使用map的函数中使用相同的 lambda函数可以正常工作而不会产生错误:

 g l = map (\(x,y) -> x==y) l

(正如图示:g [(3,4),(5,5),(7,6)]将产生[False,True,False]

示例3

此外,代码完全正常,它似乎与上面的原始f完全相同。这里的类型推断似乎有效。

 f' (x,y) = x==y

问题

所以我的问题是:为什么我们需要第一种情况下的类型声明,而不是第二种情况和第三种情况?

2 个答案:

答案 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类型推断中的反直觉规则。如果您忘记提供类型签名,有时此规则将使用“类型默认”规则填充具有特定类型的自由类型变量。