Compare commits

...

2 Commits

Author SHA1 Message Date
Oliver Payne c2f671c8dd Add test integral from the book 2023-10-19 22:29:06 +01:00
Oliver Payne 255723b1fe Fix bug where lazy pairs used excessive amounts of memory
This change makes cons a procedure created at startup, capturing the
environment once rather than each time a pair is created.
2023-10-19 22:16:25 +01:00
4 changed files with 49 additions and 8 deletions

View File

@ -6,8 +6,21 @@
(#%provide lazy-lists-program)
(define lazy-lists-program
'((define (cons x y)
(lambda (m) (m x y)))
'(
;; The cons procedure needs to be created once at interpreter
;; start up. This ensures that it captures only the initial
;; environment. Then when it is called, that environment is
;; extended to bind its parameters to the inputs.
;; Specifically, it doesn't capture the whole environment at
;; the call site of cons. The latter is what happens if we
;; create the procedure at the call site. This leads to
;; excessive memory use.
;; lazy-lambda-pair produces a specially tagged procedure that is
;; recognised as a lazy pair by the evaluator but is otherwise
;; just a normal procedure.
(define cons
(lambda (x y)
(lazy-pair-lambda (m) (m x y))))
(define (car z)
(z (lambda (p q) p)))

View File

@ -35,12 +35,13 @@
(make-procedure (lambda-parameters exp)
(lambda-body exp)
env))
((lazy-pair-lambda? exp)
(make-lazy-pair-procedure (lambda-parameters exp)
(lambda-body exp)
env))
((begin? exp)
(eval-sequence (begin-actions exp) env lazy-eval))
((cond? exp) (lazy-eval (cond->if exp) env))
((cons? exp) (eval-cons (cons-first-exp exp)
(cons-second-exp exp)
env))
((application? exp) ; clause from book
(lazy-apply (actual-value (operator exp) env)
(operands exp)
@ -57,6 +58,7 @@
procedure
(list-of-arg-values arguments env))) ; changed
((lazy-pair? procedure)
;; Skip over the lazy-pair tag if we have a lazy-pair as a procedure
(lazy-apply (lazy-pair-proc procedure)
arguments env))
((compound-procedure? procedure)
@ -95,12 +97,12 @@
(define (user-print object env)
(cond ((compound-procedure? object)
(cond ((lazy-pair? object) (display (print-lazy-pair object env)))
((compound-procedure? object)
(display (list 'compound-procedure
(procedure-parameters object)
(procedure-body object)
'<procedure-env>)))
((lazy-pair? object) (display (print-lazy-pair object env)))
(else (display object))))
(define (print-lazy-pair lazy-pair env)

View File

@ -112,6 +112,9 @@
(define (make-lambda parameters body)
(cons 'lambda (cons parameters body)))
;; Lazy-pair lambda is used to model lazy pairs
(define (lazy-pair-lambda? exp) (tagged-list? exp 'lazy-pair-lambda))
;; if
(define (if? exp) (tagged-list? exp 'if))
(define (if-predicate exp) (cadr exp))
@ -384,6 +387,10 @@
(define (compound-procedure? p)
(tagged-list? p 'procedure))
;; Lazy-pair procedure is a normal procedure tagged with lazy-pair to
;; distinguish lazy pairs from procedures
(define (make-lazy-pair-procedure parameters body env)
(make-lazy-pair (make-procedure parameters body env)))
(define (procedure-parameters p) (cadr p))
(define (procedure-body p) (caddr p))

View File

@ -45,6 +45,23 @@
(if (= a 0) 1 b))
(try 0 (/ 1 0))))
(define lazy-integral-program
'((define (integral integrand initial-value dt)
(define int
(cons initial-value
(add-lists (scale-list integrand dt)
int)))
int)
(define (solve f y0 dt)
(define y (integral dy y0 dt))
(define dy (map f y))
y)
(define solution (solve (lambda (x) x) 1 0.001))
(list-ref solution 1000)))
(#%require rackunit)
(module+ test
@ -60,7 +77,9 @@
(analyzing-eval-program (fib-program 5)))
(check-equal? (dd-eval-program (fib-program 5))
(lazy-eval-program (fib-program 5)))
(check-equal? (lazy-eval-program lazy-test-program) 1))
(check-equal? (lazy-eval-program lazy-test-program) 1)
(check-= (lazy-eval-program lazy-integral-program) 2.7169 0.01)
)
(module+ timing
(define dd-fib (time-proc 100 (lambda () (dd-eval-program (fib-program 10)))))