Lisp 设置得怎么样!在方案中定义?

Lisp 设置得怎么样!在方案中定义?,lisp,scheme,Lisp,Scheme,您将如何在Scheme中实现自己的功能?一个集合函数是一个破坏性的过程,它会更改根据以前的值定义的值。如注释中所述,set是方案中必须由实现提供的原语。类似地,在大多数编程语言中也不能实现赋值运算符=。在Common Lisp中,setf可以扩展(使用setf-expanders)以允许(setf form value)处理新类型的表单 因为方案的设置只修改变量绑定(如Common Lisp的setq),仍然值得一问,我们如何实现set car这样的函数和其他结构修改器。从某种意义上讲,这可以看

您将如何在Scheme中实现自己的功能?一个
集合函数是一个破坏性的过程,它会更改根据以前的值定义的值。

如注释中所述,
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)