【问题标题】:Compile/Evaluate operands in tailposition编译/评估尾位置的操作数
【发布时间】:2014-08-03 11:14:22
【问题描述】:

我有一个学校项目,我应该为它优化一个 Scheme 的编译器/评估器。 任务是尽可能实现尾调用优化。

我知道已知的尾调用优化如下所示:

(define (f x)
    <send some rockets into space>
    (f (+ x 1)))

但是,我也在考虑评估尾部位置的操作数。假设如下:

; The function
(define (f a b c)
    <send some monkeys into space>
    1)

; Call the function with (f 3 4 5)
(f (+ 1 2) (begin (define x 4) x) 5))

评估操作数(+ 1 2)(begin (define x 4))5 可以在尾部位置完成,对吧? 每个操作数都在它们自己的环境中进行评估。我尝试使用 DrRacket 中的常规 R5RS 并使用以下表达式:

(+ (begin (define x 5) x) x)

如果在相同的环境中计算操作数,我将能够将第一个操作数中定义的x 作为第二个操作数传递。然而这是不可能的。

那么,我假设每个操作数都可以在尾部位置进行评估是否正确?

【问题讨论】:

    标签: scheme evaluation tail-recursion


    【解决方案1】:

    “尾巴位置”总是相对于某些外部表达式。例如,考虑一下:

    (define (norm . args)
      (define (sum-of-squares sum args)
        (if (null? args)
            sum
            (let ((arg (car args)))
              (sum-of-squares (+ sum (* arg arg)) (cdr args)))))
      (sqrt (sum-of-squares 0 args)))
    

    sum-of-squares 的递归调用确实在相对于sum-of-squares 的尾部位置。但它是否在相对于norm 的尾部位置?不,因为来自sum-of-squares 的返回值被发送给sqrt,而不是直接发送给norm 的调用者。

    分析一个表达式A相对于外部表达式B是否处于尾部位置,关键是看A的返回值是否是B直接返回的,不做进一步处理。

    在您的情况下,使用您的表达式(f (+ 1 2) (begin (define x 4) x) 5)(顺便说一句,这实际上是无效的:也许您的意思是(f (+ 1 2) (let () (define x 4) x) 5)),子表达式(+ 1 2)(let () (define x 4) x)和5都不在相对于f 的尾部位置,因为必须先收集它们的值,然后然后传递给f(这尾部调用)。

    【讨论】:

      【解决方案2】:

      应用程序 (op1 op2 ...) 的所有操作数都不在尾部位置。 对于 R5RS 方案,您可以在此处查看应用程序在尾部上下文中出现的位置:

      https://groups.csail.mit.edu/mac/ftpdir/scheme-reports/r5rs-html.old/r5rs_22.html

      【讨论】:

        【解决方案3】:

        所以我终于想通了。

        在常规 R6RS 中,操作数永远不能在尾部位置求值,因为 R6RS 指定它们的求值没有严格的顺序。

        但是,在这个自建的 Scheme 评估器中,我确实指定了评估它们的顺序。因此,我可以严格定义哪个运算符是最后一个,并且可以在尾部位置进行评估。

        【讨论】:

        • 您将如何将最后一个函数调用参数评估为尾调用?请记住,在评估它之后,您仍然需要将其值传递给函数调用本身。思考这个问题的一个好方法是,你将如何在 CPS(延续传递风格)中实现整个事情?当且仅当您可以将延续直接(没有更改)作为函数调用的延续传递,那么这就是尾调用。
        • 内置的评估器确实是一个 CPS 风格的评估器。如果您的函数调用处于尾部位置,您知道您将为您的身体评估创建一个新环境。因此,不必恢复评估最后一个操作数的最后一个环境。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-09-27
        • 2011-12-08
        • 2012-07-31
        • 2023-04-11
        • 1970-01-01
        • 2019-08-12
        • 1970-01-01
        相关资源
        最近更新 更多