Implement till 4.30
This commit is contained in:
@@ -128,15 +128,6 @@
|
|||||||
|
|
||||||
(define the-global-environment (setup-environment))
|
(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)
|
(eval '(define (unless condition usual-value exceptional-value)
|
||||||
(if condition exceptional-value usual-value)) the-global-environment)
|
(if condition exceptional-value usual-value)) the-global-environment)
|
||||||
|
|
||||||
@@ -145,12 +136,12 @@
|
|||||||
(* n (factorial (- n 1)))
|
(* n (factorial (- n 1)))
|
||||||
1)) the-global-environment)
|
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")
|
(display "\nex-4.27 - lazy-evaluator\n")
|
||||||
|
|
||||||
(eval '(define count 0) the-global-environment)
|
(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)
|
(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
|
; 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
|
; w is thunk and cannot be displayed. By getting the actual value it will show
|
||||||
; 10 as expected.
|
; 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.
|
; After w is fully evaluated count is 2 as expected.
|
||||||
(assert (eval 'count the-global-environment) 2) ; count is 2
|
(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")
|
||||||
|
|
||||||
34
ex-4_31-34.scm
Normal file
34
ex-4_31-34.scm
Normal file
@@ -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")
|
||||||
|
|
||||||
4
ex-4_35-xx.scm
Normal file
4
ex-4_35-xx.scm
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
(load "util.scm")
|
||||||
|
|
||||||
|
(display "\nex-4.35\n")
|
||||||
|
|
||||||
@@ -305,9 +305,8 @@
|
|||||||
'<procedure-env>))
|
'<procedure-env>))
|
||||||
(display object)))
|
(display object)))
|
||||||
|
|
||||||
(define (eval-verbose exp env)
|
(define (eval-force exp env)
|
||||||
(let ((output (eval exp env)))
|
(let ((output (actual-value exp env)))
|
||||||
(user-print output) (newline)
|
|
||||||
output))
|
output))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user