Page 1 of 1

Pseudo-closures using gensym

Posted: Sun Apr 01, 2012 3:39 pm
by William James

Code: Select all

(define (gensym:gensym)
  (sym (string "gensym-" (inc gensym:counter))))

(define-macro (closure varval-pairs body)
  (let (alist (map (fn(x) (list (x 0) (gensym) (eval (x 1))))
                   (explode varval-pairs 2)))
    (bind (map (fn (x) (rest x)) alist))
    (dolist (x alist)
      (set-ref-all (x 0) body (x 1)))
    body))

(set 'up-down
  (closure (a 0 b 99)
    (lambda () (list (++ a) (-- b)))))

> (up-down)
(1 98)
> (up-down)
(2 97)
> (up-down)
(3 96)

> (println up-down)
(lambda () (list (++ gensym:gensym-14) (-- gensym:gensym-15)))

Re: Pseudo-closures using gensym

Posted: Wed Apr 04, 2012 2:22 pm
by William James
Slightly improved, and with an example in which two lambdas share a variable.

Code: Select all

(define-macro (closure varval-pairs)
  (let (body (cons 'begin (args))
        alist (map (fn(x) (list (x 0) (gensym) (eval (x 1))))
                   (explode varval-pairs 2)))
    (bind (map (fn (x) (rest x)) alist))
    (dolist (x alist)
      (set-ref-all (x 0) body (x 1)))
    (eval body)))

(closure (count 0)
  (setq up (fn()(++ count))) (setq down (fn()(-- count))))

: (up)
1
: (up)
2
: (up)
3
: (down)
2
: (down)
1

Re: Pseudo-closures using gensym

Posted: Wed Apr 04, 2012 3:09 pm
by Lutz
Nice application of 'gensym'.

For a different way of doing it see here:

http://www.newlisp.org/index.cgi?def-static

The difference to WJ's solution is, that it puts each function in it's own namespace via a default functor.

Re: Pseudo-closures using gensym

Posted: Wed Apr 04, 2012 8:49 pm
by William James
Thanks. I think it would be nice if gensym were built into newLISP.

Re: Pseudo-closures using gensym

Posted: Tue Apr 10, 2012 5:03 pm
by William James
It seems that gensym isn't really needed anymore.

One can simply do (sym (uuid)).

Re: Pseudo-closures using gensym

Posted: Tue Apr 10, 2012 5:18 pm
by Lutz
Yes, that works well and those things are unique ;-) On the other side the gensym function, you are using, is slightly faster and keeps the generated symbols all in the special gensym namespace. But if you are only using a few than (sym (uuid)) is more practical. Personally, I just move define-macro's (fexprs) into their own namespace, which also solves variable capture, and creates some sort of lexical closure.