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.
This commit is contained in:
Oliver Payne 2023-10-19 22:13:21 +01:00
parent a358de17d3
commit 255723b1fe
3 changed files with 29 additions and 7 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))