Answer till 4.18

main
Felix Martin 2021-01-23 14:02:35 -05:00
parent 32b43220bf
commit 4c9dc3138b
1 changed files with 91 additions and 13 deletions

View File

@ -190,7 +190,7 @@
(display "[answered]\n")
(display "\nex-4.16\n")
(display "\nex-4.16 - scan-out-defines\n")
(define (lookup-variable-value var env)
(let ((pair (find-pair-env var env)))
@ -201,20 +201,98 @@
(error "Unassigned variable" var)
value)))))
(define env-0 the-empty-environment)
(define env-1 (extend-environment '(a b) '(1 2) env-0))
(define env-2 (extend-environment '(c d) '(3 *unassigned*) env-1))
(define (scan-out-defines body)
(cond
((null? body) '())
((definition? (car body)) (cons (car body) (scan-out-defines (cdr body))))
(else (scan-out-defines (cdr body)))))
(define (get-defines body)
(cond
((null? body) '())
((definition? (car body)) (cons (car body) (get-defines (cdr body))))
(else (get-defines (cdr body)))))
(define (expression->new-expression exp)
(if (definition? exp)
(define->set exp)
exp))
(define (define->let-assignment def)
(list (definition-variable def) '*unassigned*))
(define (define->set def)
(list 'set! (definition-variable def) (definition-value def)))
(let* ((defines (get-defines body))
(let-assignments (map define->let-assignment defines))
(let-expression (list 'let let-assignments))
(expressions (map expression->new-expression body)))
(append let-expression expressions)))
(define body '((define x 3)
(if #t 1 2)
(define b 2)))
(define body
'((define x 3)
(if #t 1 2)
(define b 2)
(display "hello")))
(display (scan-out-defines body)) (newline)
(define body-transformed
'(let ((x *unassigned*)
(b *unassigned*))
(set! x 3)
(if #t 1 2)
(set! b 2)
(display "hello")))
(assert (scan-out-defines body) body-transformed)
; I would install scan-out-defines into make-procedure. We might run into a
; situation where we update the body of a procedure and call procedure-body
; twice.
(define (make-procedure parameters body env)
(list 'procedure parameters (scan-out-defines body) env))
(display "\nex-4.17\n")
; Why is there an extra frame in the transformed program? We have implemented
; let via an additional transformation. Therefore, there is another
; lambda-expression that results in an extra frame.
; Explain why this difference in environment structure can never make a
; difference in the behavior of a correct program? The transformation keeps the
; order of the assignments. Hence, the behavior will not change.
; Design a way to make the interpreter implement the ``simultaneous'' scope
; rule for internal definitions without constructing the extra frame? We could
; simply add a list of (define symbol *unassigned*) at the beginning of the
; body and get the same behavior without an extra frame.
(display "[answered]\n")
(display "\nex-4.18 - alternative-scan-out\n")
(define (solve f y0 dt)
(define y (integral (delay dy) y0 dt))
(define dy (stream-map f y))
y)
; Transformation from text:
(lambda (f y0 dt)
(let ((y '*unassigned*)
(dy '*unassigned*))
(set! y (integral (delay dy) y0 dt))
(set! dy (stream-map f y))
y))
; Transformation from this exercise:
(lambda (f y0 dt)
(let ((y '*unassigned*)
(dy '*unassigned*))
(let ((a (integral (delay dy) y0 dt))
(b (stream-map f y)))
(set! y a)
(set! dy b)
y)))
; The second transformation will not work because when b is evaluated y is not
; yet assigned. The first transformation works because y was already set when
; dy is set.
(display "[answered]\n")
(display "\nex-4.19\n")
; (display "\nex-4.20\n")