我正在编写一个方案解释器,并且遇到有效的let语句,例如:

;; should print 7
(let ((a 4) (b 3))
    (let ((a (* a a))
          (b (* b b)))
       (+ a b)
       (- a b)))

我的解释器仅实现Scheme的纯功能子集,因此不会有set!之类的副作用。在纯函数式语言中,为什么要在上述的let语句中允许多个表达式?

在编写我的解释器时,除了let中的最后一个表达式外,我是否有任何理由应该评估任何东西?看来它们永远不会影响最后评估语句的结果。

最佳答案

您是对的(几乎):如果您正在实现Scheme的纯功能子集(即,没有set!set-car!set-cdr!),那么除let中的最后一个表达式之外的任何表达式都将被丢弃,并且由于保证不会产生任何副作用,因此无视它们而没有任何危险。

但是,需要考虑一种小情况,即前面的表达式是define时:

(let ((x 3))
  (define y 4)
  (+ x y))

这既合法又有效。但是,有一些好消息-在一个块内(例如let),您必须将所有define放在顶部。就像这样,这不被视为合法方案:
(let ((x 3))
  (+ 2 3)
  (define y 4)
  (+ x y))

这意味着,在评估一个块时,您要做的就是在顶部扫描define,并将它们包装到等效的letrec表达式中,然后继续忽略除最后一个表达式之外的所有表达式(然后返回该表达式)。

编辑: antti.huima非常适合于call/cc。如果您要在实现中包括延续性,那么您实际上就无法对何时进行评估做出很多假设。

09-30 20:07
查看更多