关于《The Seasoned Schemer》中consC递归调用时N未重置的疑问
问题解答
《The Seasoned Schemer》第131-132页给出了
consC和deep的如下定义(注:原代码中cons z y应为笔误,修正为cons x y):(define consC (let ((N 0)) (lambda (x y) (set! N (add1 N)) (cons x y)))) (define deep (lambda (m) (if (zero? m) (quote pizza) (consC (deep (sub1 m)) (quote ())))))疑问:当
deep通过递归调用consC时,为何(let ((N 0))不会将N重置为0?
核心逻辑:闭包与let的执行时机
let仅在定义consC时执行一次:当你运行define consC的代码时,let ((N 0))会先触发执行,创建一个局部环境并把N初始化为0。随后这个环境里的lambda函数会被返回,赋值给consC变量。- lambda函数是闭包,会“记住”创建时的环境:这个lambda函数绑定了外层
let创建的环境,后续每次调用consC,都是调用这个lambda函数,它直接使用最初环境里的N绑定,不会重新执行外层的let。 - 递归调用复用同一个闭包:不管
deep递归多少次调用consC,每次调用的都是同一个lambda函数,操作的都是最初那个N变量。每次set! N (add1 N)都是在原有值上加1,自然不会重置为0。
举个更直观的同类例子:
(define counter (let ((n 0)) (lambda () (set! n (+ n 1)) n)))
每次调用(counter)会依次返回1、2、3……而不是每次回到0,和你的consC逻辑完全一致——let只在定义时执行一次,后续调用都是操作同一个变量。
内容的提问来源于stack exchange,提问作者Twoner
相关产品推荐
相关产品推荐

