方案中的let-over-lambda?

时间:2016-08-21 16:54:49

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

在Common Lisp中,如果我想要两个函数来共享状态,我会按如下方式执行 let over lambda

public static void addPacketsToTable(byte[] byteTable, long packetSize, long diskSpace) throws IOException {

    long packet = fetchPacketSize(); //size of packet (it is 5)
    long space = fetchDiskSpace(); //free space on my disk

    for (int i = 0; i < byteTable.length; i++) { //for another packet

        if (i < 4)
            packet *= 2;
        else
            packet *= 3;

        // packet size overflows disk
        if (packet > space)
            break;

        System.out.println(packet);

    }
}

这些函数不是(let ((state 1)) (defun inc-state () (incf state)) (defun print-state () (format t "~a~%" state)) 的本地函数 - 它们是全局函数,用于维护对共享 state 变量的引用,该变量本身在外部不可见。例如,我可以在我的代码中的其他地方执行以下操作:

let

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

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

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

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

 (print-state))     => 1

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

Scheme中是否有一种方法可以编写 let-over-lambda 表单而无需采用如此丑陋的解决方法?或者我需要写一个宏来包裹这个丑陋? (顺便说一句,我知道(define print-state #f) (define inc-state #f) (let ((state 1)) (set! print-state (lambda () (print state))) (set! inc-state (lambda () (inc! state)))) ,这不是解决这个问题的方法。)

顺便说一下,我正在使用Chicken Scheme,但我的问题应与所有方案相关。

2 个答案:

答案 0 :(得分:4)

不幸的是,顶级绑定只能在顶层进行,而程序中的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!))

实际上你不需要制作全局变量,因为你可以直接调用回报:

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

答案 1 :(得分:3)

你可以这样做:

(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中测试过)