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



我正在处理一门CS课程的作业,有点卡住了。

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

  • cdr:返回一个关联数组,该数组包含没有第一对的当前数组,如果数组为空,则返回一个空数组
  • cons:期望一对(key value)作为自变量,并通过将给定的键值对前置到当前数组来生成一个新的关联数组

基本上,关联数组是像((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))

我的问题是应该再次返回关联数组的两个函数
我再次返回dispatch的方法不起作用,因为这没有保留我对lst所做的修改
来自面向对象的语言,我试图找到一种方法来修改实例变量lst并返回"我自己";(即"对象"的修改版本(,它将是当前评估的函数(?(。不幸的是,谷歌搜索并没有找到任何有用的东西。

所以,问题是,是否真的有实现这一目标的方法,或者如果没有,是否还有我错过的另一种方法。

谢谢。

为了完整起见:@ad-absurdum的评论实际上是我问题的解决方案
然而,简单地将let包裹在define周围的方法只导致了一个";对象";被CCD_ 11消息修改。即将代码更改为该

(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

意味着CCD_ 12至CCD_;对象";。

但分配实际上希望conscdr返回关联数组的副本。因此,我简单地添加了一条copy消息,该消息从另一个对象的lst复制内部lst,并更改了conscdr以返回新的关联数组:

(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把我推向了正确的方向。

最新更新