Skip to content

Commit

Permalink
Add the lazy programming primitives of Chapter 18
Browse files Browse the repository at this point in the history
The next section will cover the Dice of Doom 2, using lazy evaluation to
allows the game use bigger boards.
  • Loading branch information
ryukinix committed Mar 15, 2017
1 parent ad049b4 commit 88cb1a5
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 2 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ A personal repository for annotation about learning lisp patterns.
The current content are answers plus code covering of the book [Land of Lisp](http://www.landoflisp.com) and the insights at the MIT 6.001 Course: Structures and Interpretations of Computer Programs.


# Land of Lisp book (reading) [374/482]
![progress](http://progressed.io/bar/77)
# Land of Lisp book (reading) [384/482]
![progress](http://progressed.io/bar/79)


- [x] Section I: Lisp is Power
Expand Down
126 changes: 126 additions & 0 deletions land-of-lisp/cap18-lazy-programming.lisp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
;; Common Lisp Script
;; Manoel Vilela

;; LAZY PROGRAMMING

;; PROG: Creating the Lazy and Force Commands
;; NOTE: This chapter has a lazy evaluation system very similar
;; to discussed on the lectures about STREAMS (6A-6B) of SICP at MIT.

(defmacro lazy (&body body)
(let ((forced (gensym))
(value (gensym)))
`(let ((,forced nil)
(,value nil))
(lambda ()
(unless ,forced
(setf ,value (progn ,@body))
(setf ,forced t))
,value))))

(defun force (lazy-value)
(funcall lazy-value))


(defmacro lazy-cons (a b)
`(lazy (cons ,a ,b)))

(defun lazy-car (x)
(car (force x)))

(defun lazy-cdr (x)
(cdr (force x)))

(defparameter *foo* (lazy-cons 4 7)) ;; => CLOSURE LAMBDA
(lazy-car *foo*) ;; => 4
(lazy-cdr *foo*) ;; => 7


(defparameter *integers* (labels ((f (n)
(lazy-cons n (f (1+ n)))))
(f 1)))

(lazy-car *integers*) ;; => 1
(lazy-car (lazy-cdr *integers*)) ;; => 2
(lazy-car (lazy-cdr (lazy-cdr *integers*))) ;; => 3

;; YES! INFINITE SEQUENCES! This is the lazy evaluation power
;; Only computes the value when needs. No recursive stack overflow.


(defun lazy-nil ()
(lazy nil))

(defun lazy-null (x)
(not (force x)))


(defun make-lazy (list)
(lazy (when list
(cons (car list)
(make-lazy (cdr list))))))


(defun take (n list)
(unless (or (zerop n)
(lazy-null list))
(cons (lazy-car list)
(take (1- n) (lazy-cdr list)))))

(take 100 *integers*) ;; => '(1 2 3 4 5 6 7 8 9 10)

(defun take-all (list)
(unless (lazy-null list)
(cons (lazy-car list)
(take-all (lazy-cdr list)))))

(take 10 (make-lazy '(q w e r t y u i o p a s d f)))
;; => (Q W E R T Y U I O P)

(take-all (make-lazy '(q w e r t y u i o p a s d f)))
;; => (Q W E R T Y U I O P A S D F)


(defun lazy-mapcar (fun list)
(lazy (unless (lazy-null list)
(cons (funcall fun (lazy-car list))
(lazy-mapcar fun (lazy-cdr list))))))

(defun lazy-mapcan (fun list)
(labels ((f (list-cur)
(if (lazy-null list-cur)
(force (lazy-mapcan fun (lazy-cdr list)))
(cons (lazy-car list-cur)
(lazy (f (lazy-cdr list-cur)))))))
(lazy (unless (lazy-null list)
(f (funcall fun (lazy-car list)))))))

(defun lazy-find-if (fun list)
(unless (lazy-null list)
(let ((x (lazy-car list)))
(if (funcall fun x)
x
(lazy-find-if fun (lazy-cdr list))))))

(defun lazy-nth (n list)
(if (zerop n)
(lazy-car list)
(lazy-nth (1- n) (lazy-cdr list))))


;; NOTE: Analogous functions mapcar, mapcan, find-if and nth for lazy lists.
(take 10 (lazy-mapcar #'sqrt *integers*))
;; => (1.0 1.4142135 1.7320508 2.0 2.236068 2.4494898 2.6457512 2.828427 3.0 3.1622777)

(take 10 (lazy-mapcan (lambda (x)
(if (evenp x)
(make-lazy (list x))
(lazy-nil)))
*integers*))
;; => (2 4 6 8 10 12 14 16 18 20)

(lazy-find-if #'oddp (make-lazy '(2 4 6 7 8 10)))
;; => 7

(lazy-nth 4 (make-lazy '(a b c d e f g)))
;; => E

0 comments on commit 88cb1a5

Please sign in to comment.