-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathex413.scm
181 lines (139 loc) · 4.98 KB
/
ex413.scm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
; Answers for 4-1-3
(load "ex412.scm")
(define (make-procedure parameters body env)
(list 'procedure parameters body env))
(define (compound-procedure? p)
(tagged-list? p 'procedure))
(define (procedure-parameters p) (cadr p))
(define (procedure-body p) (caddr p))
(define (procedure-environment p) (cadddr p))
(define (enclosing-environment env) (cdr env))
(define (first-frame env) (car env))
(define the-empty-environment '())
(define (make-frame variables values)
(cons variables values))
(define (frame-variables frame) (car frame))
(define (frame-values frame) (cdr frame))
(define (add-binding-to-frame! var val frame)
(set-car! frame (cons var (car frame)))
(set-cdr! frame (cons val (cdr frame))))
(define (extend-environment vars vals base-env)
(if (= (length vars) (length vals))
(cons (make-frame vars vals) base-env)
(if (< (length vars) (length vals))
(error "Too many arguments supplied" vars vals)
(error "Too few arguments supplied" vars vals))))
(define (lookup-variable-value var env)
(define (env-loop env)
(define (scan vars vals)
(cond ((null? vars)
(env-loop (enclosing-environment env)))
((eq? var (car vars))
(car vals))
(else (scan (cdr vars) (cdr vals)))))
(if (eq? env the-empty-environment)
(error "Unbound variable" var)
(let ((frame (first-frame env)))
(scan (frame-variables frame)
(frame-values frame)))))
(env-loop env))
(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))
(define (define-variable! var val env)
(let ((frame (first-frame env)))
(define (scan vars vals)
(cond ((null? vars)
(add-binding-to-frame! var val frame))
((eq? var (car vars))
(set-car! vals val))
(else (scan (cdr vars) (cdr vals)))))
(scan (frame-variables frame)
(frame-values frame))))
; Exercise 4.11
(define (make-binding var val)
(cons var val))
(define (make-frame vars vals)
(map make-binding vars vals))
(define (binding-variable binding)
(car binding))
(define (binding-value binding)
(cdr binding))
(define (set-binding! binding val)
(set-cdr! binding val))
(define (insert-list! seq x)
(let ((front (car seq)))
(set-car! seq x)
(set-cdr! seq (cons front (cdr seq)))))
(define (add-binding-to-frame! binding frame)
(insert-list! frame binding))
(define (find-if f seq)
(if (null? seq)
false
(let ((first (car seq)))
(if (f first)
first
(find-if f (cdr seq))))))
(define (some f seq)
(if (null? seq)
false
(let ((fx (f (car seq))))
(if fx
fx
(some f (cdr seq))))))
(define (binding-has-var var)
(lambda (binding)
(eq? (binding-variable binding) var)))
(define (find-binding-in-frame var frame)
(find-if (binding-has-var var) frame))
(define (find-binding var env)
(some (lambda (frame) (find-binding-in-frame var frame)) env))
(define (lookup-variable-value var env)
(let ((binding (find-binding var env)))
(if binding
(binding-value binding)
(error "Unbound variable" var))))
(define (set-variable-value! var val env)
(let ((binding (find-binding var env)))
(if binding
(set-binding! binding val)
(error "Unbound variable -- SET!" var))))
(define (define-variable! var val env)
(let* ((frame (first-frame env))
(binding (find-binding-in-frame var frame)))
(if binding
(set-binding! binding val)
(add-binding-to-frame! (make-binding var val) frame))))
; Exercise 4.12
;; Oops, already did that.
; Exercise 4.13
;; Interesting question. I doubt the safety of allowing a user to remove
;; variable bindings from enclosing environments, as it could effectively
;; break other pieces of code. Imagine a procedure that removed the binding
;; for '+ for example.
;; On the other hand, it's confusing that you could unbind a variable and then
;; find it is still bound, only further down the environment chain. But then
;; perhaps this is the only possible use for this function - you're not going
;; to refer to a variable again after it has been unbound otherwise, as it
;; would signal an error, so what's the point?
;; So I'm going to implement it for the first frame only.
(define (remove-if f seq)
(if (null? seq)
'()
(let ((x (car seq)))
(if (f x)
(cdr seq)
(cons x (remove-if f (cdr seq)))))))
(define (make-unbound! var env)
(set-car! env (remove-if (binding-has-var var) (first-frame env))))