Pseudo-closures using gensym

Started by William James, April 01, 2012, 08:39:36 AM

Previous topic - Next topic

William James


(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)))

William James

#1
Slightly improved, and with an example in which two lambdas share a variable.



(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

Lutz

#2
Nice application of 'gensym'.



For a different way of doing it see here:



http://www.newlisp.org/index.cgi?def-static">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.

William James

#3
Thanks.  I think it would be nice if gensym were built into newLISP.

William James

#4
It seems that gensym isn't really needed anymore.



One can simply do (sym (uuid)).

Lutz

#5
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.