如何在DrRacket Scheme中使用lambda

4

我希望你能帮我完成一个编程练习。我正在尝试创建一个这样的lambda表达式:

λz.x(yz)

我理解的是,y是一个函数,被应用于值z。然后x是一个函数,应用于函数y应用于z的输出。整个表达式的含义如下:
λz.x(yz) means: Do the following with the argument z:
  1. 将函数 y 应用到 z 上。
  2. 将函数 x 应用于第一个过程的输出结果。

我写了这个程序来尝试让Scheme完成上述所有任务:

(define (zlamb)
  (lambda (z)
    (lambda (x)
      (* (lambda (y) (* z 4)) 2))))

当我运行它时,我只得到了这个:
Welcome to DrRacket, version 5.3 [3m].
Language: R5RS; memory limit: 128 MB.
( (zlamb) 3)
procedure:...lambdaefing1.rkt:3:4
>

请问有人能告诉我我的错误在哪里吗?我想要得到的结果是 (3 * 4) * 2 = 24。所以我写了(或者我认为我写了)内部函数 y = z * 4 和外部函数 x = y(z) * 2
我在互联网上搜寻了很久,但是找不到我需要的解释。
2个回答

2
阿拉芬威说的每一句话我都能理解。然而,我仍然担心您可能误解了您的任务。
更具体地说,lambda演算本质上是scheme表达式的子集,语法略有不同。特别地,lambda演算术语λz在Scheme中写作(lambda (z)). 嗯,有一个警告,即“点”也必须翻译。
应用程序(zx)在Scheme中简单地写为(z x)。数学家很懒,有时会省略括号,因此a(bc)实际上是(a (b c))的简写。我在这里努力不直接翻译您的术语 :)
但需要注意的是,将给定的lambda演算术语直接翻译为Scheme将不是一个良好的程序,因为它包含自由引用(“未绑定变量”)y和z。

我也很担心同样的事情,正如我在第一条评论中所暗示的那样。我一直在思考是否使用lambda来处理x和y是有问题的。我非常确定yz表示将函数y应用于项z,而x(yz)表示将函数x应用于yz。所以你的意思是我必须使用(define z (functionlity this or that))才能调用(z x)吗? - TheodorN
是的,没错;您提供的 lambda 演算术语具有自由变量引用,并且除非在绑定这些变量的上下文中进行评估,否则无法进行评估。 - John Clements
谢谢John,对不起,我把变量搞混了。我应该写成...(定义y(??))以便能够调用(y z)...- 这才是我应该写的。我觉得我离理解lambda演算更近了一点。 - TheodorN

1
让我们从内部开始逐步分解你的程序:
(* z 4)

z乘以4

(lambda (y) (* z 4))

一个返回 z*4 的函数。
(* (lambda (y) (* z 4)) 2)

该函数的输出结果与2相乘。你不能将一个函数乘以2。 这很可能是导致错误的原因;也许你的意思是以下内容:
(define (zlamb)
  (lambda (z)
    ((lambda (y) (* 2 (y z))) ; Note the two parenthesis before lambda - this is a function application
      (lambda (z2) (* z2 4)))))

首先请注意,由于z2绑定到第3行中的z的值,因此两个z最终相同。实际上,它们都可以被命名为z,但我将它们命名为不同的名称以防止混淆。
进一步看来,您的基本问题在于混淆函数的名称和其参数。
(lambda (name) ...)

创建一个带有name参数的匿名函数。我们之所以能够在第三行将匿名函数称为第四行的y,是因为进行了这样的构造。该构造方式如下:
((lambda (y) ...) (lambda ...))

将第二个函数作为参数传递给第一个函数,从而将其命名为y


非常感谢你,Arafinwe,它像魔法一样奏效。通过使用 ((zlamb) 3) 调用它,结果如预期的那样是24。你很好地解释了如何嵌套lambda定义。在我的任务中,我必须进行更深层次的嵌套,但我相信我已经理解了这个想法。如果事实证明我没有,我会回来的,用一个著名的引用! - TheodorN
@TheódórNorðkvist 没问题!顺便说一下,如果你想按照正常的方式创建一个函数,正确的语法是(define (zlamb z) ...)(define zlamb (lambda (z) ...))。然后,你可以通过(zlamb 3)来调用该函数,而不是((zlamb) 3)。最后,如果你觉得这个答案有帮助,你可以点击答案旁边的勾号轮廓和“向上”按钮。这让人们知道这个问题已经被回答了。 - Lily Chung
当我获得15点声望时,我会投赞成票,再次感谢。我已经接受了答案,但这是否意味着明天我尝试进行更深层嵌套并遇到麻烦时必须提出另一个问题?只有在尝试应用并且成功或失败时,你才能知道自己是否理解了某个东西! - TheodorN
@TheódórNorðkvist 如果您有其他问题,可以提出另一个问题。但是,请考虑是否有一种将您的问题归纳为一个问题的方法。 - Lily Chung
我将我的代码更改为使用define而不是lambda,因为lambda只应用于z部分。因此,λz.x(yz)的等效形式如下,在最后一行使用参数调用。现在唯一剩下的问题是将其嵌套得更深,首先是λy.(λz.x(yz)),然后是λx.(λy.(λz.x(yz)))。(define (zlamb) (lambda (z) (define (x yz) (* yz 2) ) (define (y z) (+ z 3) ) (x (y z)) ) ) ((zlamb) 5)PS:有人知道如何分段吗? - TheodorN
@TheódórNorðkvist 只要您记得需要使用 define 给函数命名,那么在定义函数的任何地方使用 lambda 都没问题。 - Lily Chung

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接