在§5.2.1中,提供了以下函数来创建寄存器
(define (make-register name)
(let ((contents '*unassigned*))
(define (dispatch message)
(cond ((eq? message 'get) contents)
((eq? message 'set)
(lambda (value) (set! contents value)))
(else
(error "Unknown request -- REGISTER" message))))
dispatch))
但是,参数
nome
在体内没有使用,所以它基本上被函数吞没并忽略了。那么,它的相关性是什么?
确实,后来就这样用了
(define (make-new-machine)
(let ((pc (make-register 'pc))
(flag (make-register 'flag))
(stack (make-stack))
; ...
但是如果我们一开始就省略了
name
参数并像这样使用 make-register
会有什么不同吗?
(define (make-new-machine)
(let ((pc (make-register))
(flag (make-register))
(stack (make-stack))
; ...
还是我错过了什么?
我会说不,这没有什么区别。
方案可能有一些复杂的行为(这里使用的是一个,对于习惯大多数其他语言的人来说:函数携带它们的上下文,并且“堆栈”不是线性的。所以即使
make-register
调用,以及更多的 let
里面的
都完成了,因为返回的dispatch
仍然引用那个let
构建的本地上下文,所以,变量contents
的实例继续存在),它也相当“纯粹”。没有任何神秘的副作用。所以,你的推理似乎是正确的:name
没有任何作用。
我敢打赌,这与同一页中以下的练习有关:要求读者修改
make-register
以跟踪寄存器的修改(寄存器的显示名称、旧值和新值)。为此,当然,您需要手头有寄存器的名称
像这样
(define (make-register name)
(let ((contents '*unassigned*) (trace #f))
(define (dispatch message)
(cond ((eq? message 'get) contents)
((eq? message 'set)
(lambda (value)
(if trace (display `(register ,name ":" ,contents "→" ,value)))
(set! contents value)))
((eq? message 'trace-on) (set! trace #t))
((eq? message 'trace-off) (set! trace #f))
(else
(error "Unknown request -- REGISTER" message))))
dispatch))
演示:
> (define xx (make-register 'foo))
#<unspecified>
> ((xx 'set) 12)
#<unspecified>
> (xx 'trace-on)
#<unspecified>
> ((xx 'set) 15)
(register foo : 12 → 15)#<unspecified>
> (xx 'get)
15
所以,我的代码只是添加了
(if trace...)
行,以及要更改的消息 trace
。但登记册的名称已经在那里了。我敢打赌这是因为这种修改是预期的,name
就在那里。
或者,更务实的是,无论是谁编写这些练习,就像任何老师都会做的那样,首先编写完整的解决方案,然后删除某些部分以创建提供给学生的部分代码,并且忘记删除 name
:D