Haskell - Lambda演算等效语法?

时间:2013-10-06 04:23:25

标签: haskell syntax lambda lambda-calculus

在Haskell中编写一些lambda函数时,我最初编写的函数如下:

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

然而,我很快从网上的例子中注意到,这些功能经常被写成:

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

具体而言,传递给函数的每个项都有自己的\->,而不是上面。检查这些类型时,它们看起来是一样的。我的问题是,它们是相同的还是它们在某种程度上确实存在差异?不仅仅是这两个功能,而且它对一般的功能有什么影响?非常感谢!

2 个答案:

答案 0 :(得分:14)

它们是相同的,Haskell自动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 = (,)

如果您想成为惯用语,请选择第一个或最后一个。引入不必要的lambdas有利于教学curry,但在实际代码中只会增加语法杂乱。

然而,在原始的lambda演算(不是Haskell)中,大多数人手动咖喱

\a -> \b -> a b

因为人们不会手工编写很多lambda演算,而且当他们这样做时,他们倾向于坚持使用未经修饰的lambda演算来保持简单。

**以单形态限制为模,不会因类型签名而影响你。

答案 1 :(得分: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]编译Main(def0.hs,解释)
  好的,加载的模块:Main。
  *主> sum $ map(f 10000)[1..10000]
  25005000.25亿个
  *主> sum $ map(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这样的定义,您有时也可能获得良好的性能。但你不能指望它。