Implement till 4.30

main
Felix Martin 2021-01-27 10:08:51 -05:00
parent 231b4ce6c8
commit 2a04ade846
4 changed files with 109 additions and 17 deletions

View File

@ -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")

34
ex-4_31-34.scm Normal file
View 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
View File

@ -0,0 +1,4 @@
(load "util.scm")
(display "\nex-4.35\n")

View File

@ -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))