timothy235 icon

sicp-4-2-3-streams-as-lazy-lists

timothy235 | PRO | 12/19/24 01:05:41 AM UTC (Edited) | 0 ⭐ | 7217 👁️ | Never ⏰ | []
Racket |

3.55 KB

|

None

|

0 👍

/

0 👎

#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)
                          '<procedure-env>))]
        [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)

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎