【问题标题】:let-over-lambda in Scheme?计划中的让过 lambda?
【发布时间】:2016-08-21 16:54:48
【问题描述】:

在 Common Lisp 中,如果我想要两个函数共享状态,我会执行 let over lambda,如下所示:

(let ((state 1))
 (defun inc-state ()
  (incf state))
 (defun print-state ()
  (format t "~a~%" state))

这些函数不是let 的局部函数——它们是维护对共享state 变量的引用的全局函数,该变量本身从外部是不可见的。例如,我可以在代码的其他地方执行以下操作:

(print-state)       => 1
(inc-state)         => 2
(print-state)       => 2

然而,在 Scheme 中,这样的构造声明了 局部函数,这些函数从外部是不可见的:

(let ((state 1))
 (define (print-state)
  (print state))

 (print-state))     => 1

(print-state)       => error, no such variable print-state

我认为实现这种功能的唯一方法(除了在模块中使用未导出的全局变量)是这样的:

(define print-state #f)
(define inc-state #f)

(let ((state 1))
 (set! print-state (lambda () (print state)))
 (set! inc-state (lambda () (inc! state))))

Scheme 中有没有一种方法可以编写 let-over-lambda 表单,而无需求助于这种丑陋的变通方法?还是我需要编写一个宏来包装这种丑陋? (顺便说一句,我知道letrec,但这不是解决这个问题的方法。)

顺便说一句,我使用的是 Chicken Scheme,但我的问题应该与所有 Schemes 相关。

【问题讨论】:

    标签: lambda scheme chicken-scheme let-over-lambda


    【解决方案1】:

    不幸的是,顶级绑定只能是顶级绑定,而过程中的define 实际上只是letrec 的语法糖。在 Chicken Scheme 中,您有一个名为 define-values 的表单,您可以在其中执行此操作:

    (define-values (print-state inc-state)
      (let ((state 1))
        (values (lambda () (print state))
                (lambda () (inc! state)))))
    

    请注意,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!))
    

    实际上你不需要创建全局变量,因为你可以直接调用 return:

    ((dispatcher 'inc!))
    ((dispatcher 'inc!))
    ((dispatcher 'print)) ; ==> prints 3
    

    【讨论】:

    • 谢谢。 define-values 没有我的解决方案那么难看。不过,我仍然可能会编写一个宏来包装它。
    • define-values 在 R7RS 第 5.3.3 节中指定。
    【解决方案2】:

    你可以这样做:

    (define-values (inc-state print-state)
      (let ((state 1))
        (values
         (lambda () ; inc-state
           (set! state (+ 1 state)))
         (lambda () ; print-state
           (display state)
           (newline)))))
    
    > (print-state)
    1
    > (inc-state)
    > (print-state)
    2
    > state
    . . state: undefined; cannot reference an identifier before its definition
    > 
    

    (输出来自 Racket,但我也在 Chicken Scheme 中测试过)

    【讨论】:

      猜你喜欢
      • 2018-04-27
      • 2016-03-25
      • 2021-08-15
      • 2023-03-14
      • 2013-02-03
      • 1970-01-01
      • 2011-02-25
      • 2017-01-28
      • 2015-05-19
      相关资源
      最近更新 更多