Lisp 设置得怎么样!在方案中定义?
您将如何在Scheme中实现自己的功能?一个Lisp 设置得怎么样!在方案中定义?,lisp,scheme,Lisp,Scheme,您将如何在Scheme中实现自己的功能?一个集合函数是一个破坏性的过程,它会更改根据以前的值定义的值。如注释中所述,set是方案中必须由实现提供的原语。类似地,在大多数编程语言中也不能实现赋值运算符=。在Common Lisp中,setf可以扩展(使用setf-expanders)以允许(setf form value)处理新类型的表单 因为方案的设置只修改变量绑定(如Common Lisp的setq),仍然值得一问,我们如何实现set car这样的函数和其他结构修改器。从某种意义上讲,这可以看
集合代码>函数是一个破坏性的过程,它会更改根据以前的值定义的值。如注释中所述,set
是方案中必须由实现提供的原语。类似地,在大多数编程语言中也不能实现赋值运算符=
。在Common Lisp中,setf
可以扩展(使用setf
-expanders)以允许(setf form value)
处理新类型的表单
因为方案的设置代码>只修改变量绑定(如Common Lisp的setq
),仍然值得一问,我们如何实现set car这样的函数代码>和其他结构修改器。从某种意义上讲,这可以看作是变量赋值的一种泛化,但由于词汇变量(连同闭包)足以表示任意复杂的结构,因此它也可以看作是一种更特殊的情况。在Scheme中(除了像数组这样的内置原语之外),对象字段的变异是一种特殊化,因为对象可以通过词法闭包实现,并按照set代码>。这是一个典型的练习,展示了如何单独使用词法闭包实现结构,例如cons单元格。下面的示例显示了单值可变单元格的实现:
(define (make-cell value)
(lambda (op)
(case op
((update)
(lambda (new-value)
(set! value new-value)))
((retrieve)
(lambda ()
value)))))
(define (set-value! cell new-value)
((cell 'update) new-value))
(define (get-value cell)
((cell 'retrieve)))
根据这些定义,我们可以创建一个单元格,从值4
开始,使用设置值将值更新为8
代码>,并检索新值:
(let ((c (make-cell 4)))
(set-value! c 8)
(get-value c))
=> 8
如注释中所述,set
是方案中必须由实现提供的原语。类似地,在大多数编程语言中也不能实现赋值运算符=
。在Common Lisp中,setf
可以扩展(使用setf
-expanders)以允许(setf form value)
处理新类型的表单
因为方案的设置代码>只修改变量绑定(如Common Lisp的setq
),仍然值得一问,我们如何实现set car这样的函数代码>和其他结构修改器。从某种意义上讲,这可以看作是变量赋值的一种泛化,但由于词汇变量(连同闭包)足以表示任意复杂的结构,因此它也可以看作是一种更特殊的情况。在Scheme中(除了像数组这样的内置原语之外),对象字段的变异是一种特殊化,因为对象可以通过词法闭包实现,并按照set代码>。这是一个典型的练习,展示了如何单独使用词法闭包实现结构,例如cons单元格。下面的示例显示了单值可变单元格的实现:
(define (make-cell value)
(lambda (op)
(case op
((update)
(lambda (new-value)
(set! value new-value)))
((retrieve)
(lambda ()
value)))))
(define (set-value! cell new-value)
((cell 'update) new-value))
(define (get-value cell)
((cell 'retrieve)))
根据这些定义,我们可以创建一个单元格,从值4
开始,使用设置值将值更新为8
代码>,并检索新值:
(let ((c (make-cell 4)))
(set-value! c 8)
(get-value c))
=> 8
如前所述,set
是一个基元,不能作为过程实现。为了真正理解它是如何工作的,我建议您看看Lisp解释器的内部工作原理。这里有一个很好的开始:元循环评估器,特别是题为“作业和定义”的部分。以下是与问题相关部分的摘录:
(define (eval exp env)
(cond ...
((assignment? exp) (eval-assignment exp env))
...
(else (error "Unknown expression type -- EVAL" exp))))
(define (assignment? exp)
(tagged-list? exp 'set!))
(define (eval-assignment exp env)
(set-variable-value! (assignment-variable exp)
(eval (assignment-value exp) env)
env)
'ok)
(define (set-variable-value! var val env)
(define (env-loop env)
(define (scan vars vals)
(cond ((null? vars)
(env-loop (enclosing-environment env)))
((eq? var (car vars))
(set-car! vals val))
(else (scan (cdr vars) (cdr vals)))))
(if (eq? env the-empty-environment)
(error "Unbound variable -- SET!" var)
(let ((frame (first-frame env)))
(scan (frame-variables frame)
(frame-values frame)))))
(env-loop env))
最后,一个集合代码>操作只是环境中绑定值的变异。由于此级别的修改是“正常”过程的禁区,因此必须以特殊形式实施。如前所述,设置
是一个基元,不能作为过程实现。为了真正理解它是如何工作的,我建议您看看Lisp解释器的内部工作原理。这里有一个很好的开始:元循环评估器,特别是题为“作业和定义”的部分。以下是与问题相关部分的摘录:
(define (eval exp env)
(cond ...
((assignment? exp) (eval-assignment exp env))
...
(else (error "Unknown expression type -- EVAL" exp))))
(define (assignment? exp)
(tagged-list? exp 'set!))
(define (eval-assignment exp env)
(set-variable-value! (assignment-variable exp)
(eval (assignment-value exp) env)
env)
'ok)
(define (set-variable-value! var val env)
(define (env-loop env)
(define (scan vars vals)
(cond ((null? vars)
(env-loop (enclosing-environment env)))
((eq? var (car vars))
(set-car! vals val))
(else (scan (cdr vars) (cdr vals)))))
(if (eq? env the-empty-environment)
(error "Unbound variable -- SET!" var)
(let ((frame (first-frame env)))
(scan (frame-variables frame)
(frame-values frame)))))
(env-loop env))
最后,一个集合代码>操作只是环境中绑定值的变异。由于此级别的修改是“正常”程序的禁区,因此必须以特殊形式实施。不能、不能、不能。每个人都很消极!你绝对可以在球拍上做到这一点。您所需要做的就是定义自己的“lambda”宏,它引入可变单元格来代替所有参数,并为所有这些参数引入标识符宏,这样当它们用作常规varref时,它们就能正常工作。还有一套!宏,以防止扩展这些标识符宏,从而使它们可以进行变异
小菜一碟 不能,不能,不能。每个人都很消极!你绝对可以在球拍上做到这一点。您所需要做的就是定义自己的“lambda”宏,它引入可变单元格来代替所有参数,并为所有这些参数引入标识符宏,这样当它们用作常规varref时,它们就能正常工作。还有一套!宏,以防止扩展这些标识符宏,从而使它们可以进行变异
小菜一碟 集合!修改符号和位置之间的绑定(实际上是任意绑定)。编译器和解释器将处理set!不一样
解释器的环境是符号和值之间的映射。严格规定!更改符号第一次出现的值,以指向第二个操作数的计算结果。在许多实现中,您无法设置!尚未绑定的东西。在Scheme中,预期变量已绑定。阅读或玩弄示例将使您成为口译员的主要实施者
在编译器的情况下,您实际上不需要sy
(env-extend name (cell value) env)