Haskell - Lambda演算等效语法?

gol*_*enk 5 syntax lambda haskell lambda-calculus

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

tru = \t f -> t
fls = \t f -> f
Run Code Online (Sandbox Code Playgroud)

但是,我很快从网上的例子中注意到这些函数经常被写成:

tru = \t -> \f -> t
fls = \t -> \f -> f
Run Code Online (Sandbox Code Playgroud)

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

Dan*_*zer 14

它们是相同的,哈斯克尔自动咖喱的事情让一切语法不错.以下都是等效的**

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 = (,)
Run Code Online (Sandbox Code Playgroud)

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

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

\a -> \b -> a b
Run Code Online (Sandbox Code Playgroud)

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

**模拟单态限制,不管怎样都不会影响你的类型签名.


lef*_*out 6

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

f, f' :: Int -> Int -> Int
Run Code Online (Sandbox Code Playgroud)

有两个定义

f a x = ?*x
 where ? = sum [1..a]
Run Code Online (Sandbox Code Playgroud)

f' a = \x -> ?*x
 where ? = sum [1..a]
Run Code Online (Sandbox Code Playgroud)

这些肯定看起来相当,并且肯定会产生相同的结果.

GHCi,版本7.6.2:http ://www.haskell.org/ghc/:?求助
...
[1/1]编译Main(def0.hs,解释)
好的,加载的模块:Main.
*Main> sum $ map(f 10000)[
1..10000 ] 2500500025000000
*Main> sum $ map(
f'10000 )[ 1..10000 ] 2500500025000000

但是,如果你自己尝试一下,你会注意到f需要花费很多时间,而f'你会立即得到结果.原因是它f'以一种形式写入,提示GHC编译它,以便f' 10000在开始将其映射到列表之前实际进行评估.在该步骤中,?计算该值并将其存储在闭包中(f' 10000).另一方面,f简单地将其视为"两个变量的一个函数"; (f 10000)仅存储为包含参数的闭包,10000并且?最初根本不计算.仅当map应用于(f 10000)列表中的每个元素时,sum [1..a]才会计算整体,这需要一些时间用于每个元素[1..10000].同f',这是没有必要的,因为?是预先计算的.

原则上,共同子表达式消除是GHC能够自行完成的优化,因此即使使用类似的定义,您有时也可能获得良好的性能f.但你不能指望它.