2013-10-06 39 views
5

虽然在Haskell写一些lambda函数,我本来写类似的功能:Haskell - Lambda微积分等效语法?

tru = \t f -> t 
fls = \t f -> f 

不过,我很快就从例子中注意到网上,这样的功能是经常这样写:

tru = \t -> \f -> t 
fls = \t -> \f -> f 

具体,传递给函数的每个项目都有自己的\->而不是上面的。当检查它们的类型时,它们看起来是相同的。我的问题是,它们是否相同或它们在某种程度上有所不同?而不仅仅是这两个功能,但它是否对一般功能有所帮助?非常感谢!

回答

14

他们是一样的,哈斯克尔自动curries事情保持语法很好。以下都是等价的**

foo a b = (a, b) 
foo a = \b -> (a, b) 
foo = \a b -> (a, b) 
foo = \a -> \b -> (a, b) 
-- Or we can simply eta convert leaving 
foo = (,) 

如果你想成为习惯,比较喜欢第一个或最后一个。引入不必要的lambda表达式对于教卷曲是很好的,但是在实际的代码中只是增加了语法混乱。

然而,在原料演算(不哈斯克尔)与

\a -> \b -> a b 

最手动咖喱因为人们不要用手写了很多演算的,当他们这样做,他们往往坚持unsugared演算保持事情很简单。

**以modomo单态限制,它不会影响你与类型签名反正。

+0

我应该注意的是,虽然我更喜欢大多数事物的第一个或最后一个,但第二个也是有时候的替代方案,例如定义运算符时。你可以想象做一些像'f。 g = \ x - > f(g x)'。 – kqr

+0

这是正确的,但转型不是曲解;它只是语法糖。 Currying将'(a,b) - > c'转换为'a - >(b - > c)'(因此'curry ::((a,b) - > c) - > a - > b - > c ')。确实,这个符号的设计是为了简化编写curried函数。 (这可能是你想说的,但我认为这值得明确。) –

6

虽然,正如jozefg所说,它们本身是等价的,但它们可能在与局部变量绑定结合时导致不同的执行行为。考虑

f, f' :: Int -> Int -> Int 

与两个定义

f a x = μ*x 
where μ = sum [1..a] 

f' a = \x -> μ*x 
where μ = sum [1..a] 

这些看起来确实相当的,而且肯定会始终产生相同的结果。

GHCi,版本7.6.2:http://www.haskell.org/ghc/:?寻求帮助
...
[1的1]编译主(def0.hs,解释)
好吧,模块加载:主。
*主要>总和$地图(F 10000)[1..10000]
25005000.25亿
*主要>总和$映射(F” 10000)[1..10000]
25005000.25亿

但是,如果您自己尝试此操作,则会注意到f需要相当长的时间,而f'会立即得到结果。原因是f'是以提示GHC编译它的形式编写的,因此在开始将它映射到列表之前对f' 10000进行了评估。在该步骤中,计算值μ并将其存储在关闭(f' 10000)中。另一方面,f被简单地理解为“两个变量的一个函数”; (f 10000)仅作为包含参数10000的闭包存储,而μ根本不计算在内。只有当map(f 10000)应用于列表中的每个元素时,才会计算整个sum [1..a],对于[1..10000]中的每个元素需要一些时间。由于f',这是不必要的,因为μ是预先计算的。

原则上,共同子表达式消除是GHC能够自行完成的优化,所以即使使用像f这样的定义,您也可能有时会获得良好的性能。但是你不能指望它。