方案的 block 结构效率

标签 scheme lisp racket sicp

The book在第 1 章中定义了 block 结构,允许您“打包”define位于过程定义内。

考虑这个mean-square定义例如:

(define (mean-square x y) 
    (define (square x) (* x x))
    (define (average x y) (/ (+ x y) 2))
    (average (square x) (square y)))

当我运行(mean-square 2 4)时我正确地得到 10 .

我的问题是,内部定义(在这个玩具案例中的 squareaverage )是否每次运行我调用 mean-square通过口译员进行程序?如果是这样,那不是效率低下吗?如果没有,为什么?

最佳答案

如果代码编译得有些幼稚,可能会产生一些开销。原因是内部函数是在一个全新的词法环境中定义的,该环境在每次进入函数时都会重新实例化。在抽象语义中,每次调用函数时,都必须捕获新的词法闭包并将其连接到该环境框架中的正确位置。

因此,归结为编译器可以优化掉多少内容。例如,它可以注意到这两个函数实际上都没有引用周围的词法环境。 (这些函数中的xy引用是它们自己的参数,而不是周围均方的参数)。这意味着它们都被移动到顶层而不改变语义:

(define (__anon1 x) (* x x))

(define (__anon2 x y) (/ (+ x y) 2))

(define (mean-square x y)
    (define square __anon1)
    (define average __anon2)
    (average (square x) (square y)))

从现在起,squareaverage 实际上是简单的别名(由编译器生成的全局实体的别名,编译器知道它们不会被任何东西操纵)在其控制之外),它们表示的值可以通过以下方式传播:

(define (mean-square x y)
  (__anon2 (__anon1 x) (__anon1 y)))

关于方案的 block 结构效率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58827404/

相关文章:

方案:使用不带递归的抽象列表函数

linux - 在 Linux 上将 Racket 包安装为 native 可执行文件

scheme - 如何删除方案中文件中给出的单个字符?

list - 方案中的两个列表有什么区别

scheme - 为什么Scheme 有list 和quote?

list - LISP:按升序排列列表项

scheme - 使用 argmax 查找元素列表中的最大数

将 nil 参数解释为空字符串而不是 "NIL"的 Lisp 格式指令

python - 如何在方案中像 python 一样追加?

functional-programming - Racket 中的 '(撇号)是什么?