Chapter 4, Metalinguistic Abstraction

Exercise 4.32


I implemented a simple example which shows the difference between streams and lazier lazy lists, the example just demostrates that even ‘car’ is not evaluated unless it is accessed.

Streams:

1
2
3
4
5
6
7
1 ]=> (define test (lambda() (display 'invoked) 1))

;Value: test

1 ]=> (cons-stream (test) (test))
invoked
;Value 76: (1 . #[compound-procedure 77])

Lazier lazy:

1
2
3
4
5
6
7
8
9
10
11
;;; L-Eval input:
(define test (lambda() (display 'invoked) 1))

;;; L-Eval value:
ok

;;; L-Eval input:
(cons (test) (test))

;;; L-Eval value:
(compound-procedure (m) ((m x y)) <procedure-env>)

Take advantage of extra laziness

First, I thought of infinite lists in both directions but soon realised that this can be done with streams too. Similarly we can implement infinite trees too using streams(hint: cons of cons).

So, the only case where I found that extra laziness is giving extra advantage is circular dependencies which in the text is already demonstrated for solving first order differential equations.