Partial evaluation in guile › 关于部分求值 about partial evaluation [#271]

部分求值看起来很像一个常规的 自循环解释器 ( meta-circular evaluator ) 。这是一个递归函数,接受一个表达式和一个 环境 ( environment ) ,返回一个值。Guile 的部分求值器 peval 会在看到 let 和其他 绑定构造 ( binding constructs ) 时建立 词法 ( lexical ) 环境,并在看到词法引用时尝试 传播 ( propagate ) 拷贝。
A partial evaluator looks a lot like a regular meta-circular evaluator. It's a recursive function that takes an expression and an environment and yields a value. Guile's partial evaluator, peval, builds up lexical environments when it sees let and other binding constructs, and tries to propagate copies when it sees lexical references.

内联是通过 lambda 表达式的 拷贝传播 ( copy-propagation ) 实现的。正如上例中初始值 0 通过词法变量 i 传播到 (< i (len)) 一样,(lambda () (string-length s)) 传播到 len。lambda 表达式的应用可简化到与 let 绑定等价。因此,对于上面的 loop 的第一次迭代,我们有:
Inlining is facilitated by copy-propagation of lambda expressions. Just as the initial value 0 in the example above propagates through the lexical variable i to reach (< i (len)), (lambda () (string-length s)) propagates to len. Application of a lambda expression reduces to the equivalent of a let binding. So for the first iteration of loop above, we have:

(< i (len))
;; copy propagation
=> (< 0 ((lambda () (string-length s))))
;; beta-reduction
=> (< 0 (string-length s))
;; copy-propagation
=> (< 0 (string-length "yo"))
;; constant-folding
=> (< 0 2)
;; constant-folding
=> #t

这里的条件直接被折叠成了一个常数。因此我们在编译时知道要执行哪一个分支。第二个分支已经死了,所以我们会消除它。这个过程一直持续到我们最终产生结果列表为止。
In this case the condition folded to a constant, so we know at compile-time which branch to take. The second branch is dead, so we eliminate it. The process continues until we finally produce the resulting list.