Sod*_*hty 5 lambda scheme chicken-scheme let-over-lambda
在 Common Lisp 中,如果我希望两个函数共享状态,我将执行let over lambda,如下所示:
(let ((state 1))
(defun inc-state ()
(incf state))
(defun print-state ()
(format t "~a~%" state))
Run Code Online (Sandbox Code Playgroud)
这些函数不是本地函数let- 它们是全局函数,维护对共享状态变量的引用,该变量本身从外部不可见。例如,我可以在代码中的其他位置执行以下操作:
(print-state) => 1
(inc-state) => 2
(print-state) => 2
Run Code Online (Sandbox Code Playgroud)
然而,在Scheme中,这样的构造声明了从外部不可见的局部函数:
(let ((state 1))
(define (print-state)
(print state))
(print-state)) => 1
(print-state) => error, no such variable print-state
Run Code Online (Sandbox Code Playgroud)
我认为实现这种功能的唯一方法(除了在模块内使用未导出的全局变量之外)是这样的:
(define print-state #f)
(define inc-state #f)
(let ((state 1))
(set! print-state (lambda () (print state)))
(set! inc-state (lambda () (inc! state))))
Run Code Online (Sandbox Code Playgroud)
在Scheme中是否有一种方法可以编写let-over-lambda形式而无需诉诸如此丑陋的解决方法?或者我需要编写一个宏来包装这种丑陋吗?(顺便说一句,我知道letrec,这不是这个问题的解决方案。)
顺便说一句,我正在使用 Chicken Scheme,但我的问题应该与所有计划相关。
不幸的是,顶级绑定只能是顶级的,并且define在过程内部实际上只是letrec. 在“鸡计划”中,您有一个名为的表格,define-values您可以在其中执行此操作:
(define-values (print-state inc-state)
(let ((state 1))
(values (lambda () (print state))
(lambda () (inc! state)))))
Run Code Online (Sandbox Code Playgroud)
请注意,这define-values不是任何标准的一部分,尽管它似乎是常见的形式。不过,使用您用来实现它的方法来创建一个宏会很容易。对于替代解决方案,您可以返回一个调度程序,您可以调用该调度程序来访问过程:
(define dispatcher
(let ((state 1))
(lambda (msg)
(case msg
((print) (lambda () (print state)))
((inc!) (lambda () (inc! state)))))))
(define print-state (dispatcher 'print))
(define inc-state (dispatcher 'inc!))
Run Code Online (Sandbox Code Playgroud)
实际上,您不需要创建全局变量,因为您可以直接调用返回:
((dispatcher 'inc!))
((dispatcher 'inc!))
((dispatcher 'print)) ; ==> prints 3
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1320 次 |
| 最近记录: |