Racket中parameterize与shift/reset为何不支持词法作用域?
现象原因
这段代码的核心问题是动态参数绑定与延续捕获(shift/reset)的交互机制:
parameterize是动态作用域的绑定,它的生效范围仅限于当前调用栈中的代码执行路径。reset创建一个延续边界,shift会捕获从自身到reset结尾的代码作为延续k,然后直接跳出reset的上下文,回到reset外层的执行环境中运行自己的body代码。
当执行shift body里的(displayln (p))时,parameterize的动态绑定已经随着调用栈的弹出而失效,参数p回到了外层的初始值'outer。后续调用k 'done时,延续k会回到reset内部继续执行,但此时parameterize的作用域已经结束,不过这部分不影响最终的'done输出。
实现预期行为的方法
要让shift body中的p也取到'inner,需要确保shift的body代码运行在parameterize的动态环境中,以下是两种可行方案:
方案1:保存并恢复当前参数环境(推荐)
利用current-parameterization获取当前parameterize生效时的参数状态,在shift的body中恢复该状态:
(define p (make-parameter 'outer)) (reset (parameterize ([p 'inner]) (displayln (p)) ; 输出 'inner (let ([current-param (current-parameterization)]) (shift k (parameterize (#:param current-param) (displayln (p)) ; 输出 'inner (k 'done))))))
方案2:直接在shift body中重新绑定参数
如果参数值是确定的,可以直接在shift的body里再次使用parameterize绑定p:
(define p (make-parameter 'outer)) (reset (parameterize ([p 'inner]) (displayln (p)) ; 输出 'inner (shift k (parameterize ([p 'inner]) (displayln (p)) ; 输出 'inner (k 'done)))))
内容的提问来源于stack exchange,提问作者Joseph Camacho
相关产品推荐
相关产品推荐

