Haskell中何时需要lambda表单?

Haskell中何时需要lambda表单?,haskell,scheme,closures,higher-order-functions,Haskell,Scheme,Closures,Higher Order Functions,我是Haskell的新手,也是函数式编程的新手。 在其他(除了Haskell)语言中,lambda形式通常非常有用 例如,在方案中: (define (deriv-approx f) (lambda (h x) (/ (- (f (+ x h) (f x) h))) 将创建一个闭包(在函数f上)来近似导数(在值x处,间隔为h)。 但是,由于lambda表单的部分应用,在Haskell中似乎没有必要使用它: deriv-approx f h x =

我是Haskell的新手,也是函数式编程的新手。 在其他(除了Haskell)语言中,lambda形式通常非常有用

例如,在方案中:

(define (deriv-approx f)
  (lambda (h x)
    (/ (- (f (+ x h)
          (f x)
       h)))
将创建一个闭包(在函数f上)来近似导数(在值x处,间隔为h)。 但是,由于lambda表单的部分应用,在Haskell中似乎没有必要使用它:

deriv-approx f h x = ( (f (x + h)) - (f x) ) / h
Haskell中需要lambda形式的示例有哪些


编辑:将“closure”替换为“lambda form”

当您可以声明命名的curried函数(例如Haskell
deriv-approx
)时,无需使用显式lambda表达式。每个显式lambda表达式都可以替换为命名函数的部分应用程序,该命名函数将lambda表达式的自由变量作为其第一个参数

为什么要在源代码中这样做并不容易理解,但有些实现基本上是这样工作的

另外,有点离题了,下面的重写(与我刚才描述的不同)对您来说算是避免lambdas吗

deriv-approx f = let myfunc h x = (f(x+h)-(f x))/h in myfunc

两者之间没有语义上的区别

f x y z w = ...

表达式样式(显式lambdas)和声明样式之间的主要区别在于语法。重要的一种情况是,当您想使用
where
子句时:

fxy=\zw->。。。
在哪里…——x和y在范围内,z和w不在范围内
通过使用命名的局部函数或部分应用程序替换任何地方的显式lambda,确实可以编写任何Haskell程序


另请参见:。

我将给出两个稍微间接的答案

首先,考虑以下代码:

模块Lambda,其中
导数pROX f h x=((f(x+h))-(f x))/h
我在编译时告诉GHC转储一个中间表示,这大致是编译过程中使用的Haskell的简化版本,以获得以下结果:

Lambda.prox
::全部a。GHC.Real.Fractional a=>(a->a)->a->a->a
[立法会十题]
Lambda.prox=
\(@a)($D分数::GHC.Real.Fractional a)->
让{
$dNum::GHC.Num.Num a
[立法会四题]
$dNum=GHC.Real.$p1Fractional@a$dffractional}in
\(f::a->a)(h::a)(x::a)->
真的/
@a
$d零碎的
(GHC.Num.-@a$dNum(f(GHC.Num.+@a$dNum x h))(f x))
H
如果您忽略了凌乱的注释和冗长的内容,您应该能够看到编译器已经将所有内容都转换为lambda表达式。我们可以认为这是一个指示,您可能不需要手动这样做。 相反,让我们考虑一个可能需要lambda的情况。下面是一个使用折叠组成函数列表的函数:

composell::[a->a]->a->a
composell=foldr(.)id
那是什么?看不见一只羔羊!事实上,我们也可以走另一条路:

composell'::[a->a]->a->a
composell'xs x=foldr(\f g x->f(g x))id xs x
这不仅充满了lambda,它还对主函数使用了两个参数,而且还对所有函数应用了
foldr
。将
foldr
(a->b->b)->b->[a]->b
的类型与上述类型进行比较;显然,它需要三个参数,但上面我们已经将其应用于四个!更不用说累加器函数接受两个参数,但我们这里有一个三参数lambda。当然,诀窍在于两者都返回一个只接受一个参数的函数;我们只是在现场应用这一论点,而不是让lambdas胡闹


希望所有这些都能让你相信这两种形式是等价的。Lambda形式从来都不是必需的,或者可能总是必需的,因为谁能分辨出两者的区别呢?

如果只使用一次函数,例如作为映射或foldr或其他高阶函数的参数,那么使用Lambda通常比使用命名函数更好,因为很快就会清楚,该函数没有在其他任何地方使用——它不可能被使用,因为它没有名称。当您引入一个新的命名函数时,在作用域的持续时间内,您为阅读您的代码的人们提供了另一件要记住的事情。因此,严格地说,lambda从来都不是必需的,但它们通常比替代品更可取。

我不认为“结束”意味着你认为它意味着什么。这是一种实现技术,而不是一段特定的源代码。如果您部分地应用了
deriv-approx
,您的Haskell实现肯定会为您创建一个闭包。@Henning“闭包”一词已经有了各种不同的含义。我认为OP是用它来表示“lambda表达式”(这就是它在R和Scheme中的用法)。@Matt在某些情况下,您需要返回lambda。例如,
fx=let y=something\u慢x in\z->x+y
。这样写的话,只要给定x,就会计算出慢位,然后函数就可以重复使用多次。如果将z绑定移动到另一侧,则每次调用时都会计算y。@Henning仅仅因为看不到lambda,并不意味着它们不在那里。:)任何函数定义都定义为与lambda相同,请参阅Haskell报告的第4.4.3.1节。@augustss:当然。然而,正如abobe所透露的,这个问题中的OP并不关心语言定义的结构,而是想知道lambda绑定语法是否是严格必要的。那些倾向于无lambda生活方式的人可能也喜欢利用
无点
程序,另外,可以在IRC上使用lambdabot的
@pl
命令,以轻松增强其表达式的优雅性。@C.A.McCann,然后使其中一些表达式无法理解
f x y = \z w -> ...