Scheme 理解评价的环境模型

Scheme 理解评价的环境模型,scheme,evaluation,sicp,lexical-scope,Scheme,Evaluation,Sicp,Lexical Scope,SICP中的练习3.20: 绘制环境图以说明序列的评估 表达方式 (define x (cons 1 2)) (define z (cons x x)) (set-car! (cdr z) 17) (car x) 17 使用上面给出的对的过程实现 我的眼睛坏了,所以我不能画画。相反,我将尽可能地想象环境模型是如何演变的 首先,这里是过程对实现 (define (cons x y) (define (set-x! v) (set! x v)) (define (set-y! v)

SICP中的练习3.20:

绘制环境图以说明序列的评估 表达方式

(define x (cons 1 2))
(define z (cons x x))


(set-car! (cdr z) 17)

(car x) 17
使用上面给出的对的过程实现

我的眼睛坏了,所以我不能画画。相反,我将尽可能地想象环境模型是如何演变的

首先,这里是过程对实现

(define (cons x y)
  (define (set-x! v) (set! x v))
  (define (set-y! v) (set! y v))
  (define (dispatch m)
    (cond ((eq? m 'car) x)
          ((eq? m 'cdr) y)
          ((eq? m 'set-car!) set-x!)
          ((eq? m 'set-cdr!) set-y!)
          (else (error "Undefined 
                 operation: CONS" m))))
  dispatch)

(define (car z) (z 'car))
(define (cdr z) (z 'cdr))

(define (set-car! z new-value)
  ((z 'set-car!) new-value)
  z)

(define (set-cdr! z new-value)
  ((z 'set-cdr!) new-value)
  z)
每个都有一个指向全局环境的指针

这是我想象中的互动和我的解决方案

(define x (cons 1 2))
应用cons
cons创建的环境称为e1-全局环境是封闭环境
x绑定到1
y绑定到2
set-x!,快!和dispatch都有一个指向e1的指针
分派绑定到全局环境中的名称x上

(define z (cons x x))
(set-car! (cdr z) 17)
应用cons
cons create e2-全局是封闭的
相对于全局(共享)x绑定到x
相对于全局(共享)y绑定到x
set-x!,快!和dispatch都有一个指向e2的指针
分派绑定到全局环境中的名称z上

(define z (cons x x))
(set-car! (cdr z) 17)
应用套装汽车
设置汽车!创建e3-全局是封闭的
z相对于全局绑定到(cdr z)
应用cdr
cdr创建e4-全局是封闭的
相对于全局变量,z与z绑定
调度创建e5-e2是封闭的
m绑定到“cdr”
返回与e2相关的x。
x与全球共享x(以及与e1共享x)
返回e3
新值绑定到17
调度创建e6-e2是封闭的
m一定会把车开走
set-x!返回与e2有关的信息
应用set-x
set-x!创建e7-e2是封闭的
新值绑定到17
将与e2相关的x设置为17
由于x是e1,e2中的x和全局中的x共享一个指针指向e1的过程对象,因此过程对象的car发生了更改。


我希望这是可以理解的。我的解决方案正确吗?

以下是您具体问题的答案

我将全局变量
x
重命名为
v
,以避免混淆

应用cons
cons创建的环境称为e1-全局环境是封闭环境
x绑定到1
y绑定到2
set-x!,快!和dispatch都有一个指向e1的指针
dispatch绑定到全局环境中的名称
v

(define z (cons x x))
(set-car! (cdr z) 17)

应用cons
cons创建e2-全局是封闭的
就全局(共享)而言,x与v绑定
y相对于全局(共享)绑定到v
set-x!,快!和dispatch都有一个指向e2的指针
dispatch绑定到全局环境中的名称
z

(define z (cons x x))
(set-car! (cdr z) 17)

应用套装汽车
设置汽车!创建e3-全局是封闭的

没有

(在下文中,不使用代码格式标记,以将视觉受损者的噪音降至最低)

首先,对(cdrz)进行评估。它相当于(z’cdr)。z绑定到e2帧的调度。这将在收到消息“cdr”后发送给e2的y。这将访问e2环境帧中的y插槽,该插槽保存全局环境中的v值

接下来,对(设置car!v 17)进行评估。它相当于((v’set car!)17)。v绑定到e1帧的调度。收到了“定置车”!消息,发送到e1的set-x!功能。因此,这将使用e1的set-x!调用(set-x!17)!。这又在环境帧e1内调用(set!x 17)。因此,它访问并修改环境帧e1中的“x”插槽

从现在起,任何使用v的未来操作都将反映此更改,因为v表示帧e1,并且该帧已更改。e1帧在“x”下的存储值不再是1,而是17

通过访问这些值不会创建新的环境帧。这些值引用的隐藏帧将被访问,并且可能会被修改

只有
cons
会创建新的隐藏环境帧,这些帧会附加到新创建的“cons”值(即调度函数)


下面是首先写的,作为一个例子。不幸的是,我怀疑它对视觉(如果有的话)更有帮助。它包括一步一步的评估过程

我将首先重新编写您的
cons
函数,作为等效函数,只是稍微详细一点

(define cons 
   (lambda (x y)
     (letrec ([set-x! (lambda (v) (set! x v))]
              [set-y! (lambda (v) (set! y v))]
              [dispatch 
                  (lambda (m)
                    (cond ((eq? m 'car) x)
                          ((eq? m 'cdr) y)
                          ((eq? m 'set-car!) set-x!)
                          ((eq? m 'set-cdr!) set-y!)
                          (else (error 
                            "CONS: ERROR: unrecognized op name" m))))])
        dispatch)))
更强调它的值方面,lambda函数也是值,它们可以被创建、命名和返回。现在,上面的意思是在我们的代码中编写
(cons12)
与编写相同

(let ([x 1]
      [y 2])
     (letrec ; EXACTLY the same code as above
             ([set-x! (lambda (v) (set! x v))]
              [set-y! (lambda (v) (set! y v))]
              [dispatch 
                  (lambda (m)
                    (cond ((eq? m 'car) x)
                          ((eq? m 'cdr) y)
                          ((eq? m 'set-car!) set-x!)
                          ((eq? m 'set-cdr!) set-y!)
                          (else (error 
                            "CONS: ERROR: unrecognized op name" m))))])
        dispatch))
当对其进行评估时,将创建两个绑定–留出两个位置,一个我们稍后可以称为
x
,另一个为
y
–并且每个绑定都填充了相应的值:对于
x
,将1放入其中,对于
y
–2。到目前为止还不错

然后,输入
letrec
表单。它创建它的绑定,它的三个特殊位置,名为
set-x
set-y
调度
。每个位置都填充了相应的值,即创建的相应lambda函数

这里是关键部分:因为它是在外部
(let([x1][y2])
表单内部完成的,所以这三个函数中的每一个都知道这两个地方,这两个绑定,用于
x
y
。当
set-x使用
x
y
set-y
调度
,实际指的是
x
y
的位置

这三个函数中的每一个都知道由
(letrec…
创建的其他两个函数及其自身。这就是
letrec
的工作原理。使用
let
,它创建的名称只知道封闭环境

那之后呢
(define v (cons 1 2))
=>
{dispatch where {E2: set-x!=..., set-y!=..., dispatch=...
          where {E1: x=1, y=2 }}}
;
(define z (cons v v))
=>
{dispatch where {E5: set-x!=..., set-y!=..., dispatch=...
          where {E4: x=v, y=v
          where {E3: v={dispatch where {E2: set-x!=..., set-y!=..., dispatch=...
                                 where {E1: x=1, y=2 }}} }}}}
(((z 'cdr) 'set-car!) 17)
=>
...... (z 'cdr)
...... =>
...... {(dispatch 'cdr) where {E5: set-x!=..., set-y!=..., dispatch=...
......     where {E4: x=v, y=v
......     where {E3: v={dispatch where {E2: set-x!=..., set-y!=..., dispatch=...
......                            where {E1: x=1, y=2 }}} }}}}
...... =>
...... { x where {E5: set-x!=..., set-y!=..., dispatch=...
......     where {E4: x=v, y=v
......     where {E3: v={dispatch where {E2: set-x!=..., set-y!=..., dispatch=...
......                            where {E1: x=1, y=2 }}} }}}}
...... =>
...... { v where {E3: v={dispatch where {E2: set-x!=..., set-y!=..., dispatch=...
......                            where {E1: x=1, y=2 }}} }}
...... =>
...... {dispatch where {E2: set-x!=..., set-y!=..., dispatch=... where {E1: x=1, y=2 }}}
...... <=
... ((z 'cdr) 'set-car!)
... =>
... {(dispatch 'set-car!) where {E2: set-x!=..., set-y!=..., dispatch=...
...                               where {E1: x=1, y=2 }}}
... =>
... { set-x! where {E2: set-x!=..., set-y!=..., dispatch=... where {E1: x=1, y=2 }}}
... <=
(((z 'cdr) 'set-car!) 17)
=>
{ (set-x! 17) where {E2: set-x!=..., set-y!=..., dispatch=... where {E1: x=1, y=2 }}}
=>
{ (set! x 17) where {E2: set-x!=..., set-y!=..., dispatch=... where {E1: x=1, y=2 }}}
=>
{ (set! x 17) where {E1: x=1, y=2 }}
=>
{E1: x=17, y=2 }