SICP - 10 - 求值的环境模型
7/28/2024
Concepts
- Environment: “places” in which values can be stored
- Frames: A table (possibly empty) of bindings, which associate variable names with their corresponding values
- Procedure: a pair consisting of some code and a pointer to an environment
- Procedures are created in one way only: by evaluating an -expression
- Code is obtained from the text of the -expression
- Environment is the environment in which the -expression was evaluated to produce the procedure
The Rules for Evaluation
- Rule 1: A procedure object is applied to a set of arguments by constructing a frame, binding the formal parameters of the call, and then evaluating the body of the procedure in the context of the new environment constructed. The new frame has as its enclosing environment the environment part of the procedure object being applied.
- Rule 2: A lambda-expression is evaluated relative to a given environment as follows:a new procedure object is formed. combining the text (code) of the lambda-expression with a pointer to the environment of evaluation.
Actions and Identity
- We say that an action. A. had an effect on a object, X, (or equivalently, that X was changed by A) if some property, P. which was true of X before A because false of X after A
- We say that two objects. X and Y, are the same if any action which has an effect on X has the same effect on Y
练习 3.9
递归与迭代
(define (factorial n)
(if (= n 1)
1
(* n (factorial (- n 1)))))
digraph {
rankdir=LR
subgraph cluster_global {
global_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
factorial
label = "Global"
}
fact_pair[shape=record, label="<env> Env | <body> Body"]
factorial -> fact_pair
fact_pair:env -> global_handle
fact_body[label="(if (= n 1))\l 1\l (* n (factorial (- n 1)))"]
fact_pair:body -> fact_body
subgraph cluster_frame1 {
label = "Frame 1"
frame1_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
fact_n_6[label="n = 6"]
step1[color="white", label="(* 6 (factorial 5))"]
}
frame1_handle -> global_handle;
E1[color="white"]
E1 -> frame1_handle
subgraph cluster_frame2 {
label = "Frame 2"
frame2_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
fact_n_5[label="n = 5"]
step2[color="white", label="(* 5 (factorial 4))"]
}
frame2_handle -> global_handle;
E2[color="white"]
E2 -> frame2_handle
subgraph cluster_frame3 {
label = "Frame 3"
frame3_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
fact_n_4[label="n = 4"]
step3[color="white", label="(* 4 (factorial 3))"]
}
frame3_handle -> global_handle;
E3[color="white"]
E3 -> frame3_handle
subgraph cluster_frame4 {
label = "Frame 4"
frame4_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
fact_n_3[label="n = 3"]
step4[color="white", label="(* 3 (factorial 2))"]
}
frame4_handle -> global_handle;
E4[color="white"]
E4 ->frame4_handle
subgraph cluster_frame5 {
label = "Frame 5"
frame5_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
fact_n_2[label="n = 2"]
step5[color="white", label="(* 2 (factorial 1))"]
}
frame5_handle -> global_handle;
E5[color="white"]
E5 -> frame5_handle
subgraph cluster_frame6 {
label = "Frame 6"
frame6_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
fact_n_1[label="n = 1"]
step6[color="white", label="1"]
}
frame6_handle -> global_handle;
E6[color="white"]
E6 -> frame6_handle
}
(define (factorial n)
(fact-iter 1 1 n))
(define (fact-iter product counter max-count)
(if (> counter max-count)
product
(fact-iter (* counter product)
(+ counter 1)
max-count)))
digraph {
rankdir=LR
subgraph cluster_global {
global_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
factorial
fact_iter
label = "Global"
}
fact_pair[shape=record, label="<env> Env | <body> Body"]
factorial -> fact_pair
fact_body[label="(if (= n 1))\l 1\l (* n (factorial (- n 1)))"]
fact_pair:body -> fact_body
fact_pair:env -> global_handle
fact_iter_pair[shape=record, label="<env> Env | <body> Body"]
fact_iter -> fact_iter_pair
fact_iter_pair:env -> global_handle
fact_iter_body[label="(if (> counter max-count)\l product\l (fact_iter (* counter product)\l (+ counter 1)\l max-count)))"]
fact_iter_pair:body -> fact_iter_body
subgraph cluster_frame1 {
label = "Frame 1"
frame1_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
frame1_values[label="product = 1 \n counter = 1 \n max-count = 6"]
step1[color="white", label="(fact-iter 1 2 6)"]
}
frame1_handle -> global_handle;
E1[color="white"]
E1 -> frame1_handle
subgraph cluster_frame2 {
label = "Frame 2"
frame2_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
frame2_values[label="product = 1 \n counter = 2 \n max-count = 6"]
step2[color="white", label="(fact-iter 2 3 6)"]
}
frame2_handle -> global_handle;
E2[color="white"]
E2 -> frame2_handle
subgraph cluster_frame3 {
label = "Frame 3"
frame3_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
frame3_values[label="product = 2 \n counter = 3 \n max-count = 6"]
step3[color="white", label="(fact-iter 6 4 6)"]
}
frame3_handle -> global_handle;
E3[color="white"]
E3 -> frame3_handle
subgraph cluster_frame4 {
label = "Frame 4"
frame4_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
frame4_values[label="product = 6 \n counter = 4 \n max-count = 6"]
step4[color="white", label="(fact-iter 24 5 6)"]
}
frame4_handle -> global_handle;
E4[color="white"]
E4 ->frame4_handle
subgraph cluster_frame5 {
label = "Frame 5"
frame5_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
frame5_values[label="product = 24 \n counter = 5 \n max-count = 6"]
step5[color="white", label="(fact-iter 120 6 6)"]
}
frame5_handle -> global_handle;
E5[color="white"]
E5 -> frame5_handle
subgraph cluster_frame6 {
label = "Frame 6"
frame6_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
frame6_values[label="product = 120 \n counter = 6 \n max-count = 6"]
step6[color="white", label="(fact-iter 720 7 6)"]
}
frame6_handle -> global_handle;
E6[color="white"]
E6 -> frame6_handle
subgraph cluster_frame7 {
label = "Frame 7"
frame7_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
frame7_values[label="product = 720 \n counter = 7 \n max-count = 6"]
step7[color="white", label="720"]
}
frame7_handle -> global_handle;
E7[color="white"]
E7 -> frame7_handle
}
练习 3.10
局部状态变量
(define (make-withdraw initial-amount)
(let ([balance initial-amount])
(lambda (amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance)
"Insufficient funds"))))
(define W1 (make-withdraw 100))
(W1 50)
(define W2 (make-withdraw 100))
- 在全局环境中定义
make-withdraw
,make-withdraw
的值可看作一个 表达式 - 对
make-withdraw
的 表达式求值,得到一个序对,序对的Env
部分指向make_withdraw
所在的全局环境,Body
部分指向 表达式的代码 - 在参数
initial-amount = 100
上应用make-withdraw
,建立一个新框架Frame1
,Frame1
的外围环境是全局环境,形式参数init-amount
约束于对应的实际参数100
,将该框架称为环境E1
make-withdraw
的的过程体是一个 表达式,在环境E1
下求值,得到一个序对(<let-lambda>
指向的序对),其Env
部分指向当前环境Frame1
- 在参数
balance = 100
上应用<let-lambda>
,得到一个新框架Frame2
,并绑定Frame1
为外围环境,并约束balance
的值为100
,称该框架为环境E2
<let-lambda>
的过程体为一个 表达式,在环境E2
下求值,得到一个序对,其Env
部分指向当前环境Frame2
- 将得到的序对作为返回值返回,在全局环境中将
W1
绑定到返回值上 - 在参数
amount = 50
上应用W1
,建立一个新框架Frame3
,将Frame3
的的外围环境绑定为Frame2
,将该框架称为环境E3
- 在环境
E3
下执行函数体,顺着当前环境的框架链条向上寻找balance
,在Frame2
中找到,(>= balance amount)
的条件满足,将Frame2
中的balance
更新为50
W2
的获取过程与上述类似,注意在应用过程时要建立新的框架
digraph {
rankdir=LR
subgraph cluster_global {
global_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
make_withdraw
W1
W2
label = "Global"
}
make_withdraw_pair[shape=record, label="<env> Env | <body> Body"]
make_withdraw -> make_withdraw_pair
make_withdraw_body[label="参数: initial_value \l (lambda (balance) ...)"]
make_withdraw_pair:body -> make_withdraw_body
make_withdraw_pair:env -> global_handle
subgraph cluster_frame1 {
label = "Frame 1"
frame1_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
frame1_values[label="initial-amount = 100"]
let_lambda[label="<let-lambda>"]
}
let_lambda -> let_lambda_pair
let_lambda_pair[shape=record, label="<env> Env | <body> Body"]
let_lambda_pair:env -> frame1_handle
let_lambda_body[label="参数: balance \l (lambda (amount) ...)"]
let_lambda_pair:body -> let_lambda_body
frame1_handle -> global_handle;
E1[color="white"]
E1 -> frame1_handle
subgraph cluster_frame2 {
label = "Frame 2"
frame2_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
frame2_values[label="balance = 100"]
}
frame2_handle -> frame1_handle;
E2[color="white"]
E2 -> frame2_handle
inner_lambda_pair[shape=record, label="<env> Env | <body> Body"]
inner_lambda_pair:env -> frame2_handle
inner_lambda_body[label="参数: amount \l (if (> balance amount) ..."]
inner_lambda_pair:body -> inner_lambda_body
W1 -> inner_lambda_pair
subgraph cluster_frame3 {
label = "Frame 3"
frame3_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
frame3_values[label="amount = 50"]
}
frame3_handle -> frame2_handle;
E3[color="white"]
E3 -> frame3_handle
subgraph cluster_frame4 {
label = "Frame 4"
frame4_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
frame4_values[label="initial-amount=100"]
let_lambda2[label="<let-lambda>'"]
}
frame4_handle -> global_handle
E4[color="white"]
E4 -> frame4_handle
let_lambda2_pair[shape=record, label="<env> Env | <body> Body"]
let_lambda2_pair:env -> frame4_handle
let_lambda2_pair:body -> let_lambda_body
let_lambda2 -> let_lambda2_pair
subgraph cluster_frame5 {
label = "Frame 5"
frame5_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
frame5_values[label="blanace = 100"]
}
frame5_handle -> frame4_handle
E5[color="white"]
E5 -> frame5_handle
inner_lambda2[shape=record, label="<env> Env | <body> Body"]
inner_lambda2:env -> frame5_handle
inner_lambda2:body -> inner_lambda_body
W2 -> inner_lambda2
}
练习 3.11
内部定义
清晰起见,以下省略求值 表达式所产生的序对
(define (make-account balance)
(define (withdraw amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance)
"Insufficient funds"))
(define (deposit amount)
(set! balance (+ balance amount))
balance)
(define (dispatch m)
(cond [(eq? m 'withdraw) withdraw]
[(eq? m 'deposit) deposit]
[else (error "Unknown request -- MAKE-ACCOUNT" m)]))
dispatch)
digraph {
rankdir=LR
subgraph cluster_global {
label = "Global"
global_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
make_account
}
subgraph cluster_frame1 {
label = "Frame 1"
frame1_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
frame1_values[label="balance = 50 \n withdraw ... \n deposit ... \n dispatch ..."]
}
frame1_handle -> global_handle
E1[color="white"]
E1 -> frame1_handle
subgraph cluster_frame2 {
label = "Frame 2"
frame2_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
frame2_values[label="m = 'deposit"]
}
frame2_handle -> frame1_handle
E2[color="white"]
E2 -> frame2_handle
subgraph cluster_frame3 {
label = "Frame 3"
frame3_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
frame3_values[label="amount = 40"]
}
frame3_handle -> frame1_handle
E3[color="white"]
E3 -> frame3_handle
subgraph cluster_frame4 {
label = "Frame 4"
frame4_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
frame4_values[label="m = 'withdraw"]
}
frame4_handle -> frame1_handle
E4[color="white"]
E4 -> frame4_handle
subgraph cluster_frame5 {
label = "Frame 5"
frame5_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
frame5_values[label="amount = 60"]
}
frame5_handle -> frame1_handle
E5[color="white"]
E5 -> frame5_handle
subgraph cluster_frame6 {
label = "Frame 6"
frame6_handle[label="", style="filled", fillcolor="black", width=0.1, height=0.1]
frame6_values[label="balance = 100 \n withdraw ... \n deposit ... \n dispatch ..."]
}
frame6_handle -> global_handle
E6[color="white"]
E6 -> frame6_handle
}