Implement till 4.30
parent
231b4ce6c8
commit
2a04ade846
|
@ -128,15 +128,6 @@
|
|||
|
||||
(define the-global-environment (setup-environment))
|
||||
|
||||
(eval '(define (assert a b)
|
||||
(cond ((equal? a b) (display "[ok]"))
|
||||
(else
|
||||
(display "[error] ")
|
||||
(display a)
|
||||
(display " != ")
|
||||
(display b)))
|
||||
(newline)) the-global-environment)
|
||||
|
||||
(eval '(define (unless condition usual-value exceptional-value)
|
||||
(if condition exceptional-value usual-value)) the-global-environment)
|
||||
|
||||
|
@ -145,12 +136,12 @@
|
|||
(* n (factorial (- n 1)))
|
||||
1)) the-global-environment)
|
||||
|
||||
(eval '(assert (factorial 5) 120) the-global-environment)
|
||||
(assert (eval-force '(factorial 5) the-global-environment) 120)
|
||||
|
||||
(display "\nex-4.27 - lazy-evaluator\n")
|
||||
|
||||
(eval '(define count 0) the-global-environment)
|
||||
(eval '(define (id x) (set! count (+ count 1)) x) the-global-environment))
|
||||
(eval '(define (id x) (set! count (+ count 1)) x) the-global-environment)
|
||||
(eval '(define w (id (id 10))) the-global-environment)
|
||||
|
||||
; I expected count to be 0 here, but it is 1 in reality. I think when
|
||||
|
@ -160,12 +151,76 @@
|
|||
|
||||
; w is thunk and cannot be displayed. By getting the actual value it will show
|
||||
; 10 as expected.
|
||||
(assert (actual-value 'w the-global-environment) 10)
|
||||
(assert (eval-force 'w the-global-environment) 10)
|
||||
|
||||
; After w is fully evaluated count is 2 as expected.
|
||||
(assert (eval 'count the-global-environment) 2) ; count is 2
|
||||
|
||||
(display "\nex-4.28\n")
|
||||
(display "\nex-4.28 - eval-actual-value\n")
|
||||
|
||||
(display "\nex-4.29\n")
|
||||
; Replace actual-value with eval in line 53 and see how this fails: unknown
|
||||
; procedure (thunk + ...).
|
||||
(assert (eval '((lambda (op a b) (op a b)) + 1 2) the-global-environment) 3)
|
||||
|
||||
(display "\nex-4.29 - memoization\n")
|
||||
|
||||
; Calculating fibonacci numbers recursively will run much slow without
|
||||
; memoization.
|
||||
(define the-global-environment (setup-environment))
|
||||
(eval '(define (fib n)
|
||||
(if (< n 2)
|
||||
1
|
||||
(+ (fib (- n 2)) (fib (- n 1)))))
|
||||
the-global-environment)
|
||||
(eval '(define count 0) the-global-environment)
|
||||
(eval '(define (id x) (set! count (+ count 1)) x) the-global-environment)
|
||||
(eval '(define (square x) (* x x)) the-global-environment)
|
||||
|
||||
(assert (eval '(square (id 10)) the-global-environment) 100)
|
||||
(assert (eval 'count the-global-environment) 1)
|
||||
(assert (eval '(fib 10) the-global-environment) 89)
|
||||
|
||||
; If we implemented force-it without memoization count would be 2 because the
|
||||
; id-procedure gets evaluated twice:
|
||||
; (assert (eval 'count the-global-environment) 2)
|
||||
|
||||
(display "\nex-4.30 - eval-sequence\n")
|
||||
|
||||
; a. Ben is right because primitive procedures are executed right away.
|
||||
|
||||
; b.
|
||||
|
||||
(eval
|
||||
'(define (p1 x)
|
||||
(set! x (cons x '(2)))
|
||||
x)
|
||||
the-global-environment)
|
||||
|
||||
(eval
|
||||
'(define (p2 x)
|
||||
(define (p e)
|
||||
e
|
||||
x)
|
||||
(p (set! x (cons x '(2)))))
|
||||
the-global-environment)
|
||||
|
||||
; With the text implementation the result is (1 2) because set! gets evaluated
|
||||
; right away. p2 defines another procedure which has the consequence that e is
|
||||
; evaluated lazily. Hence, the intial value of e 1 is returned.
|
||||
|
||||
(assert (eval-force '(p1 1) the-global-environment) '(1 2))
|
||||
(assert (eval-force '(p2 1) the-global-environment) 1)
|
||||
|
||||
; If we change the implementation of eval-sequence the behavior of p1 is the
|
||||
; same. However, since e gets evaluated right away in p2 the result is the same
|
||||
; as for p1.
|
||||
|
||||
; c. Evaluating the statements right away does not change the behavior, because
|
||||
; force-it is called either way.
|
||||
|
||||
; d. I think the lazy implementation should be kept as it is. Primitive
|
||||
; procedures work as expected and if we have a lazy language it is consistent
|
||||
; to not force the evaluation of unused thunks.
|
||||
|
||||
(display "[done]\n")
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
(load "util.scm")
|
||||
(load "misc/evaluator.scm")
|
||||
|
||||
(display "\nex-4.31 - explicit-laziness\n")
|
||||
|
||||
; Exercise 4.31. The approach taken in this section is somewhat unpleasant,
|
||||
; because it makes an incompatible change to Scheme. It might be nicer to
|
||||
; implement lazy evaluation as an upward-compatible extension, that is, so that
|
||||
; ordinary Scheme programs will work as before. We can do this by extending the
|
||||
; syntax of procedure declarations to let the user control whether or not
|
||||
; arguments are to be delayed. While we're at it, we may as well also give the
|
||||
; user the choice between delaying with and without memoization. For example,
|
||||
; the definition
|
||||
|
||||
;(define (f a (b lazy) c (d lazy-memo))
|
||||
; ...)
|
||||
|
||||
; would define f to be a procedure of four arguments, where the first and third
|
||||
; arguments are evaluated when the procedure is called, the second argument is
|
||||
; delayed, and the fourth argument is both delayed and memoized. Thus, ordinary
|
||||
; procedure definitions will produce the same behavior as ordinary Scheme,
|
||||
; while adding the lazy-memo declaration to each parameter of every compound
|
||||
; procedure will produce the behavior of the lazy evaluator defined in this
|
||||
; section. Design and implement the changes required to produce such an
|
||||
; extension to Scheme. You will have to implement new syntax procedures to
|
||||
; handle the new syntax for define. You must also arrange for eval or apply to
|
||||
; determine when arguments are to be delayed, and to force or delay arguments
|
||||
; accordingly, and you must arrange for forcing to memoize or not, as
|
||||
; appropriate.
|
||||
|
||||
; (display "\nex-4.32\n")
|
||||
; (display "\nex-4.33\n")
|
||||
; (display "\nex-4.34\n")
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
(load "util.scm")
|
||||
|
||||
(display "\nex-4.35\n")
|
||||
|
|
@ -305,9 +305,8 @@
|
|||
'<procedure-env>))
|
||||
(display object)))
|
||||
|
||||
(define (eval-verbose exp env)
|
||||
(let ((output (eval exp env)))
|
||||
(user-print output) (newline)
|
||||
(define (eval-force exp env)
|
||||
(let ((output (actual-value exp env)))
|
||||
output))
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue