Return Scheme中有状态函数的修改版本

Return modified version of stateful function in Scheme

我正在完成我的一门 CS 课程的作业,但有点卡住了。

作业是创建关联数组的面向消息的实现。这些数组应该理解(除其他外)以下消息:

基本上,关联数组是像 ((a 1) (b 7) (c 4) (a 6) (c 5) (d 4) (b 2)) 这样的对列表,在这种情况下,字符是键,整数是值。

要实现面向消息的样式,我们应该使用一个带有两个参数的 dispatch 函数(其中第二个参数仅供理解它的消息使用)。

我目前的情况是这样的:

(define (make-empty-as)
    (define (dispatch msg arg)
        (let ((lst '()))
            (cond
                ((eq? msg 'cdr)
                    (cond ((not (null? lst)) (set! lst (cdr lst))))
                    dispatch)
                ((eq? msg 'cons)
                    (cond ((= (length arg) 2) (set! lst (append lst (list arg)))))
                     dispatch)
                ;; other messages ...
                (else (error "Don't understand " msg)))))
    dispatch)

例如,要构建上面的数组,我们可以这样做:

(define a1 (make-empty-as))
(define a2 (a1 'cons '(b 2)))
(define a3 (a2 'cons '(d 4)))
(define a4 (a3 'cons '(c 5)))
(define a5 (a4 'cons '(a 6)))
(define a6 (a5 'cons '(c 4)))
(define a7 (a6 'cons '(b 7)))
(define a8 (a7 'cons '(a 1)))
;; a8 should now have the list ((a 1) (b 7) (c 4) (a 6) (c 5) (d 4) (b 2))
(a8 'cdr 'dummy) ;; should be the list ((b 7) (c 4) (a 6) (c 5) (d 4) (b 2))

我的问题是这两个函数应该再次 return 一个关联数组。
我对 return dispatch 的方法再次不起作用,因为这不会保留我对 lst.
所做的修改 来自面向对象的语言,我试图找到一种方法来修改实例变量 lst 和 return “我自己”(即“对象”的修改版本),这将是当前的功能评估(?)。不幸的是,谷歌搜索并没有带来任何帮助。

所以,问题是是否真的有办法实现这一目标,如果没有,我是否还缺少另一种方法。

谢谢。

只是为了完整性:@ad absurdum 的评论实际上是我的问题的解决方案。
然而,简单地将 let 包裹在 define 周围的方法导致只有一个“对象”被 cons 消息修改。 IE。将代码更改为此

(define (make-empty-as)
    (let ((lst '()))
        (define (dispatch msg arg)
            (cond
                ((eq? msg 'cdr)
                    (cond ((not (null? lst)) (set! lst (cdr lst))))
                    dispatch)
                ((eq? msg 'cons)
                    (cond ((= (length arg) 2) (set! lst (append (list arg) lst))))
                     dispatch)
                ((eq? msg 'print) (display lst) (newline)) ;; added for debugging
                (else (error "Don't understand " msg))))
        dispatch))

和运行

(define a1 (make-empty-as))
(a1 'print 'dummy)
(define a2 (a1 'cons '(b 2)))
(a2 'print 'dummy)
(define a3 (a2 'cons '(d 4)))
(a3 'print 'dummy)
(define a4 (a3 'cons '(c 5)))
(a4 'print 'dummy)
(define a5 (a4 'cons '(a 6)))
(a5 'print 'dummy)
(define a6 (a5 'cons '(c 4)))
(a6 'print 'dummy)
(define a7 (a6 'cons '(b 7)))
(a7 'print 'dummy)
(define a8 (a7 'cons '(a 1)))
(a8 'print 'dummy)
(a1 'print 'dummy)

导致以下输出

() ;; a1
((b 2)) ;; a2
((d 4) (b 2)) ;; a3
((c 5) (d 4) (b 2)) ;; a4
((a 6) (c 5) (d 4) (b 2)) ;; a5
((c 4) (a 6) (c 5) (d 4) (b 2)) ;; a6
((b 7) (c 4) (a 6) (c 5) (d 4) (b 2)) ;; a7
((a 1) (b 7) (c 4) (a 6) (c 5) (d 4) (b 2)) ;; a8
((a 1) (b 7) (c 4) (a 6) (c 5) (d 4) (b 2)) ;; a1

意思是所有a1a8实际上代表同一个“对象”。

但赋值实际上需要 conscdr 到 return 副本 的关联数组。因此,我简单地添加了一个 copy 消息,从另一个对象的 lst 复制内部 lst 并将 conscdr 更改为 return 新关联数组:

(define (make-empty-as)
    (let ((lst '()))
        (define (dispatch msg arg)
            (cond
                ((eq? msg 'cdr)
                    (cond
                        ((not (null? lst)) ((make-empty-as) 'copy (cdr lst)))
                        (else (make-empty-as))))
                ((eq? msg 'cons)
                    (cond
                        ((= (length arg) 2) ((make-empty-as) 'copy (append (list arg) lst)))
                        (else (make-empty-as))))
                ((eq? msg 'print) (display lst) (newline))
                ((eq? msg 'copy)
                    (cond
                        ((list? arg) (set! lst arg))
                        (else (set! lst '())))
                    dispatch)
                (else (error "Don't understand " msg))))
        dispatch))

运行

(define a1 (make-empty-as))
(a1 'print 'dummy)
(define a2 (a1 'cons '(b 2)))
(a2 'print 'dummy)
(define a3 (a2 'cons '(d 4)))
(a3 'print 'dummy)
(define a4 (a3 'cons '(c 5)))
(a4 'print 'dummy)
(define a5 (a4 'cons '(a 6)))
(a5 'print 'dummy)
(define a6 (a5 'cons '(c 4)))
(a6 'print 'dummy)
(define a7 (a6 'cons '(b 7)))
(a7 'print 'dummy)
(define a8 (a7 'cons '(a 1)))
(a8 'print 'dummy)
(a1 'print 'dummy)

现在又给出了想要的结果

() ;; a1
((b 2)) ;; a2
((d 4) (b 2)) ;; a3
((c 5) (d 4) (b 2)) ;; a4
((a 6) (c 5) (d 4) (b 2)) ;; a5
((c 4) (a 6) (c 5) (d 4) (b 2)) ;; a6
((b 7) (c 4) (a 6) (c 5) (d 4) (b 2)) ;; a7
((a 1) (b 7) (c 4) (a 6) (c 5) (d 4) (b 2)) ;; a8
() ;; a1

再次感谢 @ad absurdum 将我推向正确的方向。