我正在编写一个Scheme解释器,我面临一个有效的let语句,例如:
;; should print 7 (let ((a 4) (b 3)) (let ((a (* a a)) (b (* b b))) (+ a b) (- a b)))
我的解释器只实现了Scheme的一个纯函数子集,因此不存在set!等副作用.在纯函数式语言中,为什么要在let语句中允许多个表达式,如上所述?
在编写我的翻译时,除了let中的最后一个表达式,我还有什么理由可以评估它吗?似乎它们永远不会影响最后评估的陈述的结果.
实际上你不能"丢弃"除最后一个语句以外的所有语句,因为之前的语句可能是非终止的.例如:
(define (func) (func)) (let () (func) ;; does not return 1)
在这里,如果你没有(func)
评估,你得到错误的结果(这是1),而你应该得到非终止计算.
另一个问题是call/cc(call-with-current-continuation)(是的,它属于功能子集)可用于实际从非尾部位置返回计算,例如:
(call-with-current-continuation (lambda (ret) (let () (ret 3) 4)))
这将返回3而不是4.这仍然是纯粹的功能.
注意BTW (let () x y z)
等同于单语句形式(let () (begin x y z))
所以真正的问题是如果你需要begin
:)