使用/不使用lambdas定义函数

时间:2015-08-28 12:18:21

标签: haskell lambda ghc

如果我使用lambda表达式定义函数或者在使用GHC编译模块时没有这样做会有什么不同呢

f :: A -> B
f = \x -> ...

VS

f :: A -> B
f x = ...

我认为我看到它有助于编译器内联函数,但除此之外,如果我从第一个版本更改为第二个版本,它会对我的代码产生影响。

我正在尝试理解其他人的代码,并在第一种方式而非第二种方式中推断出为什么要定义此功能的原因。

2 个答案:

答案 0 :(得分:8)

为了回答这个问题,我用两种方式编写了一个小程序,并查看了Core生成的内容:

f1 :: Int -> Int
f1 = \x -> x + 2
{-# NOINLINE f1 #-}

f2 :: Int -> Int
f2 x = x + 2
{-# NOINLINE f2 #-}

我通过运行ghc test.hs -ddump-simpl获得核心。相关部分是:

f1_rjG :: Int -> Int
[GblId, Arity=1, Str=DmdType]
f1_rjG =
  \ (x_alH :: Int) -> + @ Int GHC.Num.$fNumInt x_alH (GHC.Types.I# 2)

f2_rlx :: Int -> Int
[GblId, Arity=1, Str=DmdType]
f2_rlx =
  \ (x_amG :: Int) -> + @ Int GHC.Num.$fNumInt x_amG (GHC.Types.I# 2)

结果是相同的,所以回答你的问题:从一种形式转换到另一种形式没有影响。

话虽如此,我建议查看左下方的答案,该答案涉及实际存在差异的情况。

答案 1 :(得分:5)

首先,第二种形式更灵活(它允许你进行模式匹配,下面的其他条款用于替代案例)。

当只有一个子句时,它实际上等同于一个lambda ...除非你有一个where范围。即,

f = \x -> someCalculation x y
 where y = expensiveConstCalculation

更有效
f x = someCalculation x y
 where y = expensiveConstCalculation

因为在后者中,当您使用不同的参数评估y时,始终会重新计算f。在lambda表单中,y被重用:

  • 如果f的签名是单态的,则fconstant applicative form,即全局常量。这意味着y在整个程序中共享,someCalculation的每次调用只需要f重新执行y。这通常是理想的性能,当然它也意味着f不断占用内存。
  • 如果map f longList是多态的,那么它实际上隐含地是您使用它的类型的函数。这意味着你不能获得全球共享,但是如果你写的是y,然后在映射到列表之前,只需要计算一次Sub PT_cache_clear() For Each pc In ActiveWorkbook.PivotCaches pc.Clear Next pc End Sub

这是性能差异的要点。现在,当然GHC可以重新排列内容,因为它保证结果是相同的,如果认为效率更高,它可能总是将一种形式转换为另一种形式。但通常情况并非如此。