我正在编写一个方案解释器,并且遇到有效的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。如果您要在实现中包括延续性,那么您实际上就无法对何时进行评估做出很多假设。