#lang racket (require "4-2-3-lazy-lists-repl-program.rkt") ;;;;;;;;;; ;; 4.32 ;; ;;;;;;;;;; ;; The difference is that the car is lazy as well as the cdr. For example the book ;; example of integral and solve now works without having to delay the integrand. ;; Also, as the book mentions, if you implemented a binary tree as a cons of the left ;; branch with the right branch, you could now have lazy trees. ;;;;;;;;;; ;; 4.33 ;; ;;;;;;;;;; ;; The quoted clause in my-eval had to be changed to take the environment as a ;; parameter: ;; [(quoted? expr) (text-of-quotation expr env)] ;; text-of-quotation also had to be changed: (define (list->lazy-list xs) (if (empty? xs) empty (list 'my-cons (first xs) (list->lazy-list (rest xs))))) (define (text-of-quotation expr env) (define toq (second expr)) (if (pair? toq) (my-eval (list->lazy-list toq) env) toq)) ;; text-of-quotation needs access to the environment because a lazy pair is ;; implemented as a compound procedure and compound procedures possess an enclosing ;; environment. ;;;;;;;;;; ;; 4.34 ;; ;;;;;;;;;; ;; A lazy list is an application of my-cons. ;; Change the definition of my-cons to use a distinctive parameter name: '(define (my-cons x y) (lambda (i-am-a-lazy-list) (i-am-a-lazy-list x y))) ;; Now we have a way to recognize lazy-lists: (define (lazy-list? obj) (and (compound-procedure? obj) (eq? (first (procedure-parameters obj)) 'i-am-a-lazy-list))) ;; To select the my-car and my-cdr of a lazy list, look up x and y in the environment ;; of the lazy list. I got this idea from Felix021 on schemewiki. (define (lazy-list-my-car lzl) (force-it (lookup-variable-value 'x (procedure-environment lzl)))) (define (lazy-list-my-cdr lzl) ; never display this (force-it (lookup-variable-value 'y (procedure-environment lzl)))) ;; To make lazy-list-my-cdr work, I had to make the empty list self-evaluating: (define (self-evaluating? expr) (or (number? expr) (string? expr) (empty? expr))) ;; Now we can transfrom a lazy list into something printable: (define (lazy-list->list lzl [num 10]) ; do not accumulate more than num elements (define (loop acc rst n) (cond [(zero? n) (reverse (cons '... acc))] [(empty? rst) (reverse acc)] [(self-evaluating? rst) (reverse (cons rst (cons "." acc)))] [else (loop (cons (lazy-list-my-car rst) acc) (lazy-list-my-cdr rst) (sub1 n))])) (loop empty lzl num)) ;; Because of infinite lists, we terminate the display after at most ten elements. ;; Change user-print in repl operations to handle lazy lists: (define (user-print object) (cond [(lazy-list? object) (displayln (lazy-list->list object))] [(compound-procedure? object) (displayln (list 'compound-procedure (procedure-parameters object) (procedure-body object) '))] [else (displayln object)])) ;; (driver-loop) ;; ;;; L-Eval input: ;; '(1 2 3) ;; ;;; L-Eval value: ;; (1 2 3) ;; ;;; L-Eval input: ;; (my-cons 1 2) ;; ;;; L-Eval value: ;; (1 . 2) ;; ;;; L-Eval input: ;; '(1 2 3 4 5 6 7 8 9 10 11 12) ;; ;;; L-Eval value: ;; (1 2 3 4 5 6 7 8 9 10 ...) ;; ;;; L-Eval input: ;; '(1 "a" 23 "xyz") ;; ;;; L-Eval value: ;; (1 a 23 xyz) ;; ;;; L-Eval input: ;; (my-cons 1 "a") ;; ;;; L-Eval value: ;; (1 . a)