RSS Feed

Lisp Project of the Day

lazy

You can support this project by donating at:

Donate using PatreonDonate using Liberapay

Or see the list of project sponsors.

lazylanguage

Documentation😀
Docstrings😀
Tests 🥺
Examples😀
RepositoryActivity🥺
CI 🥺

This is a small library by @codeninja_blog. It provides only a macro to wrap and remember any form and a function to force its evaluation.

For example, let's create a few functions which accept and return lazy objects:

POFTHEDAY> (defun request-name ()
             (lazy:lazy
               (format t "What is your name?~%")
               (read-line)))


POFTHEDAY> (defun greet (name)
             (lazy:lazy
               (format nil "Hello ~A!~%"
                       (lazy:lazy-value name))))

POFTHEDAY> (greet (request-name))
#<LAZY::THUNK UNREALIZED>

POFTHEDAY> (lazy:lazy-value *)
What is your name?
Bob
"Hello Bob!
"

;; Second attempt to get the greeting value
;; is not request for the user's name:
POFTHEDAY> (lazy:lazy-value **)
"Hello Bob!
"

Or we can build a simple lazy sequences library.

This function will create a sequence of numbers:

POFTHEDAY> (defun make-lazy-sequence (&optional (start 0) (step 1))
             (lazy:lazy
               (values start
                       (make-lazy-sequence (+ start step)
                                           step))))

This one will skip a number of items:

POFTHEDAY> (defun lazy-skip (n lazy-sequence)
             (lazy:lazy
               (loop do
                 (multiple-value-bind (item rest)
                     (lazy:lazy-value lazy-sequence)
                   (when (zerop n)
                     (return (values item rest)))
                   (decf n)
                   (setf lazy-sequence rest)))))

And this one will force lazy evaluation and transform the sequence into the list:

POFTHEDAY> (defun lazy-to-list (n lazy-sequence)
             (loop with result = nil
                   do (multiple-value-bind (item rest)
                          (lazy:lazy-value lazy-sequence)
                        (when (zerop n)
                          (return (nreverse result)))
                        (push item result)
                        (setf lazy-sequence rest)
                        (decf n))))

And of cause we need a generic map function to apply transformations:

POFTHEDAY> (defun lazy-mapcar (func sequence)
             (lazy:lazy
               (multiple-value-bind (item rest)
                   (lazy:lazy-value sequence)
                 (values (funcall func item)
                         (lazy-mapcar func rest)))))

Here is how we can apply these functions to process a lazy sequence:

POFTHEDAY> (make-lazy-sequence)

POFTHEDAY> (lazy-skip 5 *)

POFTHEDAY> (lazy-mapcar (lambda (x)
                          (format t "Multiplying ~A to ~A~%"
                                  x x)
                          (* x x))
                        *)

POFTHEDAY> (lazy-to-list 3 *)
Multiplying 5 to 5
Multiplying 6 to 6
Multiplying 7 to 7
Multiplying 8 to 8
(25 36 49)

But this will work only with my pull request which makes the lazy-value return all values, returned by original form.

Anyway, lazy is a small and very nice library. Thank you, @codeninja_blog.


Brought to you by 40Ants under Creative Commons License