[clazy-devel] Fwd: More interesting stuff

szergling senatorzergling at gmail.com
Sun Mar 8 09:23:52 UTC 2009


---------- Forwarded message ----------
From: szergling <senatorzergling at gmail.com>
Date: Wed, Feb 25, 2009 at 11:51 PM
Subject: Re: More interesting stuff
To: Marco Antoniotti <marcoxa at gmail.com>
Cc: clazy-devel at common-lisp.net


On Thu, Feb 19, 2009 at 5:05 PM, Marco Antoniotti wrote:

> only recently I did some hacking again.

Good to hear back from you. I wasn't sure if the clazy mailing lists
are working. I did forward my previous email to the list, but it
hasn't gone through. I'll try and forward this to the list again.

>
> I was dabbling with the idea of removing the LAZY:CALLS as well but
> maybe through a reader macro, although I loathe doing so, as then you
> must hijack either [] or {}.  In your examples

Yeah, I'm not too keen on that either. On the one hand, the
code-walker example would allow laziness to be specified once only for
all sub-forms. On the other hand, with reader macros, we get
fine-grained control, allowing us to switch between eager & laziness
(hopefully seamlessly, and without too much confusion? -- is this
good?).

>   (letrec/lazy ((x {lcons 1 {lcons 1 {list+ x {lcdr x}}}}))
>      (list-force n x))
>
> But I am not so sure about it.  Also, I would just change your
> letrec/lazy to let/lazy (my initial implementation is a little silly).

letrec was basically Scheme inspired. Perhaps under laziness, let is
the same as letrec? I haven't though too much about this, so I don't
really know...

(let ((x 1))
 (let ((x x))
   x))

(let ((x 1))
 (letrec ((x x))
   x))

I would expect different behaviour from each alternative under eager
evaluation, but under laziness, I'm not so sure...

I guess the value of (letrec ((x x)) x) under eager evaluation could
be undefined? As an example, under the only Scheme I have handy at the
moment, Elk,

> (letrec ((x x)) x)
()

Although I think it should be undefined...

> Finally, I know it may be a little far fetched, but you can actually
> be more devious :)
>
> (def-lazy-function cons (x y) (cons (delay x) (delay y))
> (def-lazy-function car (x) (force (car x)))
> (def-lazy-function cdr (x) (force (cdr x)))
> ... ect ...
>
> def-lazy-function (unlike deflazy) does not define a strict version of
> the function, thus it does not redefine regular strict functions.  Now
> your code can be written as
>
>   (letrec/lazy ((x {cons 1 {cons 1 {list+ x {cdr x}}}}))
>      (list-force n x))

The laziness becomes even more invisible if we can slap on a
with-laziness very very far outside this form, assuming it is
embedded/nest deeply amongs other sexps:

(let ((x (cons 1 (cons 1 (list+ x (cdr x))))))
  ...)

I guess it effectively makes a lazy Lisp...

Yeah, I basically cannot decide on what form of lazy call syntax looks
best. Perhaps this
decision should be delayed further?

clazy is a nice twist on laziness, I'll have to find more time to play
with it someday. Thanks!


> On Fri, Nov 7, 2008 at 4:31 AM, szergling <senatorzergling at gmail.com> wrote:
>
>     Hi again,
>
>     I have just hacked up something that I thought was cool. It began with
>     this observation:
>
>     We can form "infinite" lists using recursive definitions. Here's how
>     one can make an infinite list of 1's. First some utility functions:
>
>     (deflazy lcons (x y)
>      (cons (delay x)
>            (delay y)))
>
>     (deflazy lcar (cons)
>      (force (car cons)))
>
>     (deflazy lcdr (cons)
>      (force (cdr cons)))
>
>     (deflazy list-times (n list)
>      (if (null list)
>          '()
>          (call 'lcons
>                (* n (call 'lcar list))
>                (call 'list-times n
>                      (call 'lcdr list)))))
>
>     (deflazy list+ (list1 list2)
>      (if (null list1)
>          '()
>          (call 'lcons
>                (+ (call 'lcar list1)
>                   (call 'lcar list2))
>                (call 'list+
>                      (call 'lcdr list1)
>                      (call 'lcdr list2)))))
>
>     ;; Force and collect the first n items.
>     (defun list-force (n list)
>      (loop
>         with l = list
>         for i below n
>         for first-time-p = t then nil
>         while l
>
>         unless first-time-p
>         do (setf l (lcdr l))
>
>         collect (lcar l)))
>
>     ;; --------------------
>
>     An infinite list of 1's.
>
>     (let ((x nil))
>      (flet ((get-x () x)
>             ((setf get-x) (val)
>               (setf x val)))
>        (symbol-macrolet ((x (get-x)))
>          (setf x
>                (call 'lcons 1 x))
>          x)))
>
>     Codify the pattern above:
>
>     ;; (put 'letrec/lazy 'common-lisp-indent-function 1)
>
>     (defmacro letrec/lazy (bindings &body body)
>      (let* ((bindings (mapcar (lambda (x)
>                                 (if (and (list x)
>                                          (= 2 (length x)))
>                                     x
>                                     (list x nil)))
>                               bindings))
>             (vars (mapcar #'car bindings))
>             (val-forms (mapcar #'cadr bindings))
>             (gvars (mapcar (lambda (x)
>                              (gensym (symbol-name x)))
>                            vars))
>             (fun-names (mapcar (lambda (x)
>                              (gensym (format nil "GET-~a" x)))
>                            vars)))
>        (with-unique-names (value)
>          (flet ((make-getter (var fun-name)
>                   `(,fun-name () ,var))
>                 (make-setter (var fun-name)
>                   `((setf ,fun-name) (,value)
>                     (setf ,var ,value)))
>                 (make-symbol-macro (var fun-name)
>                   `(,var (,fun-name)))
>                 (make-initialiser (var val-form)
>                   `(setf ,var ,val-form)))
>            `(let ,vars
>               (flet (,@(mapcar #'make-getter vars fun-names)
>                      ,@(mapcar #'make-setter vars fun-names))
>                 (symbol-macrolet ,(mapcar #'make-symbol-macro
>                                           vars fun-names)
>                   ,@(mapcar #'make-initialiser vars val-forms)
>                   , at body)))))))
>
>     Some examples:
>
>     (letrec/lazy ((x (call 'lcons 1 x)))
>      (list-force 10 x))
>     (1 1 1 1 1 1 1 1 1 1)
>
>     ;; List elements keep doubling.
>     (letrec/lazy ((x (call 'lcons 1 (call 'list-times 2 x))))
>      (list-force 10 x))
>     (1 2 4 8 16 32 64 128 256 512)
>
>     ;; Fibonacci. Just like in those Haskell examples.
>     (letrec/lazy ((x (call 'lcons 1
>                           (call 'lcons 1
>                                 (call 'list+
>                                       x (call 'lcdr x))))))
>      (list-force 20 x))
>     (1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765)
>
>     I think we will have to remove explicit "calls" by using a code
>     walker. In the meantime, here's a quick hack to demonstrate what the
>     code might look like without all those calls.
>
>     (defmacro with-laziness ((&rest options) &body body)
>      (declare (ignore options))
>      (labels ((transform (form)
>                 (if (atom form)
>                     form
>                     (destructuring-bind (name . args)
>                         form
>                       (if (lazy-function-name-p name)
>                           `(call ',name ,@(mapcar #'transform args))
>                           form)))))
>        (cons 'progn
>              (mapcar #'transform body))))
>
>     (letrec/lazy ((x (with-laziness ()
>                       (lcons 1 (lcons 1 (list+ x (lcdr x)))))))
>      (list-force 20 x))
>
>     With a proper code-walker, with-laziness can wrap the whole form like
>     this:
>
>     (with-laziness ()
>      (letrec/lazy ((x (lcons 1 (lcons 1 (list+ x (lcdr x))))))
>        (list-force 20 x)))
>
>     Don't you think this is cool?
>
>     Unfortunately, there's a risk of infinite recursive/loops with this type
>     of construct.
>
>     I have to admit (see eg the list-times and list+ functions) that
>     I've still not completely "assimilated" the evaluation rules in this
>     new delayed DSL subset of Common Lisp, but what's there is enough for
>     me to test things out. Nice work!
>




More information about the Clazy-devel mailing list