【问题标题】:How to implement iteration of lambda calculus using scheme lisp?如何使用方案 lisp 实现 lambda 演算的迭代?
【发布时间】:2017-08-29 05:28:00
【问题描述】:

我正在尝试学习 lambda 演算和 Scheme Lisp。关于 lambda 演算的教程可以在这里找到http://www.inf.fu-berlin.de/lehre/WS03/alpi/lambda.pdf

我面临的问题是我不知道如何正确实现迭代。

(define (Y y) (((lambda (x) (y (x x))) (lambda (x) (y (x x))))))
(define (sum r n) ((is_zero n) n0 (n succ (r (pred n)))))
(display ((Y sum) n5))

我总是得到这个错误:

正在中止!:超出最大递归深度

我知道问题在于评估顺序:该方案首先解释(Y sum),这导致无限递归:

((Y sum) n5) -> (sum (Y sum) n5) -> ((sum (sum (Y sum))) n5) -> .... (infinite recursion)

但我想要

((Y sum) n5) -> ((sum (Y sum) n5) -> (n5 succ ((Y sum) n4)) -> .... (finite recursion)

我该如何解决这个问题?谢谢。

【问题讨论】:

    标签: recursion scheme lambda-calculus mit-scheme y-combinator


    【解决方案1】:

    Lambda 演算是一种正常的顺序评估语言。因此,它与 Haskell 的共同点多于 Scheme,后者是一种应用顺序评估语言。

    在 DrRacket 中,你有一个方言 #lang lazy,它与你得到的 Scheme 一样接近,但由于它很懒,你有正常的订单评估:

    #!lang lazy
    
    (define (Y f) 
      ((lambda (x) (x x)) 
       (lambda (x) (f (x x)))))
    
    (define sum
      (Y (lambda (r)
           (lambda (n)
             ((is_zero n) n0 (n succ (r (pred n))))))))
    
    (church->number (sum n5))
    

    如果您无法更改语言,则可以将其包装在 lambda 中以使其延迟。例如。

    如果r 是元数 1 的函数,它是 lambda 演算中的所有函数,那么 (lambda (x) (r x)) 是对 r 的完美重构。它将停止无限递归,因为您只获得包装器,并且即使评估是急切的,它也只会在您每次递归时应用它。 Eager 语言中的 Y 组合子称为 Z:

    (define (Z f) 
      ((lambda (x) (x x)) 
       (lambda (x) (f (lambda (d) ((x x) d))))))
    

    如果你想在 Scheme 中做 Z,例如使用多参数递归函数,你可以使用其余参数:

    (define (Z f) 
      ((lambda (x) (x x)) 
       (lambda (x) (f (lambda args (apply (x x) args))))))
    
    ((Z (lambda (ackermann)
          (lambda (m n)
            (cond
              ((= m 0) (+ n 1))
              ((= n 0) (ackermann (- m 1) 1))
              (else (ackermann (- m 1) (ackermann m (- n 1))))))))
     3
     6) ; ==> 509
    

    【讨论】:

    • 我记得曾经纠正过 Lambda 演算没有指定的评估策略——任何策略都可以使用。如果我能找到它,我会链接它。
    • @naomik Lambda 演算执行是通过 beta 减少,直到它不能再执行,因此我们达到了正常形式。 Applicative order reduction may not terminate, even when the term has a normal form
    • @naomik 我很确定您在这里是正确的,并且没有固定的还原策略是 LC 首先能够调查各种还原策略的属性的原因。 en.wikipedia.org/wiki/Lambda_calculus#Reduction_strategies 说,例如,“完全减少 beta ......基本上意味着缺乏任何特定的减少策略”等。
    • @willness 但这意味着即使我们知道程序会以一种减少策略终止,它是否会停止也不确定?
    • @Sylwester 我认为这只是意味着减少策略的选择超出了 LC 本身。一个程序可能会以一种选择终止,而不会以另一种选择终止。当然,给定的编程语言通常会包含这种选择。
    【解决方案2】:

    延迟计算的标准方法是通过 eta-expansion:

    (define (Y y) ((lambda (x) (y (x x))) (lambda (x) (y (x x) )) ))
    =~
    (define (YC y) ((lambda (x) (y (lambda (z) ((x x) z))))
                    (lambda (x) (y (lambda (z) ((x x) z)))) ))
    

    这样

    ((YC sum) n5) 
    =
      (let* ((y sum)
             (x (lambda (x) (y (lambda (z) ((x x) z)))) ))
        ((y (lambda (z) ((x x) z))) n5))
    = 
      (let ((x (lambda (x) (sum (lambda (z) ((x x) z)))) ))
        ((sum (lambda (z) ((x x) z))) n5))
    = 
      ...
    

    并评估(sum (lambda (z) ((x x) z))) 只是使用 lambda 函数,该函数包含自应用程序,但尚未调用它。

    展开会切中要害

    (n5 succ ((lambda (z) ((x x) z)) n4))
    =
    (n5 succ ((x x) n4))    where x = (lambda (x) (sum (lambda (z) ((x x) z))))
    

    只有在那时才会执行自我应用程序。

    因此,(YC sum) = (sum (lambda (z) ((YC sum) z))),而不是发散(在评估的应用顺序下)(Y sum) = (sum (Y sum))

    【讨论】:

    • 您好,我在 Clojure 而不是 Scheme 中遇到了完全相同的问题。我尝试了 YC 组合器,但仍然得到 StackOverflowError。我得出的结论是,如果不评估表达式,我们就不能进行递归。递归函数可能带有if 语句。在 clojure 中,if 不是函数,它是一个特殊的关键字,当条件为真时不会评估第二个分支。但是if 是 lambda 演算中的一个函数,其中分支是参数。 Clojure 急切地评估参数,其中一个是递归调用,因此 StackOverflowError
    • @DemeterPurjon 不,在 Scheme if 中也不会评估其所有参数。 factorial 里面有if,可以用YC 编码。此外,在 LC(lambda 演算)中,如果不需要,则不会评估任何内容,它是“正常顺序评估”,即“按名称评估”(“懒惰”)。你的代码是什么?您可以尝试询问有关 SO 的问题,包括所有相关代码,:) 期望的结果以及实际发生的情况。如果你这样做了,请在这里@ ping 我,这样我就不会错过了! :)
    • 感谢@will-ness!你的说法听起来比我的更合法。我会问一个问题并联系你:) 谢谢
    • 嘿@WillNess。我问了一个新问题:stackoverflow.com/questions/46061344/…。感谢您的帮助!
    • @DemeterPurjon 正如我所怀疑的,Clojure 有其自身的特定问题,即缺乏尾调用优化(我不使用 Clojure)。希望您能从熟悉 Clojure 的人那里获得帮助,以便在那里实现您自己的蹦床。 Scheme下TCO有保障,YC代码依赖它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多