在Haskell中编写一些lambda函数时,我最初编写的函数如下:
tru = \t f -> t
fls = \t f -> f
然而,我很快从网上的例子中注意到,这些功能经常被写成:
tru = \t -> \f -> t
fls = \t -> \f -> f
具体而言,传递给函数的每个项都有自己的\
和->
,而不是上面。检查这些类型时,它们看起来是一样的。我的问题是,它们是相同的还是它们在某种程度上确实存在差异?不仅仅是这两个功能,而且它对一般的功能有什么影响?非常感谢!
答案 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
这样的定义,您有时也可能获得良好的性能。但你不能指望它。