Re: returning multiple distinct closures
On Thu, Feb 23, 2012 at 09:48:14PM -0300, José Romero wrote: Your problem is using the quote function instead of making a copy of the list on return, this rewritten version should work: (de lazy Prg (list NIL (list 'job (list 'quote (cons 'Value delayed)) (list 'if '(== Value delayed) (list 'setq 'Value (cons 'run Prg)) 'Value ) ) ) ) That's right. A slight simplification might be directly using 'prog' instead of 'run' (list 'setq 'Value (cons 'prog Prg)) This has the advantage that instead of (setq foo (lazy (prog (prinl !) 2))) You can write (setq foo (lazy (prinl !) 2)) or even better (def 'foo (lazy (prinl !) 2)) : (pp 'foo) (de foo NIL (job '((Value . delayed)) (if (== Value delayed) (setq Value (prog (prinl !) 2)) Value ) ) ) - foo : (foo) ! - 2 : (foo) - 2 Cheers, - Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: returning multiple distinct closures
I've been thinking on the problem a bit and found another way to tackle it, using this incredibly *UGLY* function (all of them formatted as the output of 'pp, I have no idea how to make it more aesthetically pleasing): (de lazy Prg (let L (box (cons)) (con (val L) (list (list 'cdar (list 'con L (list 'list (list 'cons ''quote (cons 'prog Prg)) ) ) ) ) ) (val L) ) ) - lazy : (setq A (lazy (prinl Computing...) 42)) - (NIL (cdar (con $384526428 (list (cons 'quote (prog (prinl Computing...) 42)) : (A) Computing... - 42 : (A) - 42 : A - (NIL '42) As you can see, the resulting lambda modifies itself to become just the quoted result on the first call. The way 'lazy works is by first boxing a cons pair to form the head of the lambda expression. Then it concatenates a function body to that head that is itself a call to 'con to replace itself with the computed result in a quote. The box symbol is not necessary at all, I included it to make the resulting expression printable. This version works the same, but crashes print (rather, puts it in an infinite loop) if you use it in the repl without a 'nil guard. (de lazy Prg (let L (cons) (con L (list (list 'cdar (list 'con (cons 'quote L) (list 'list (list 'cons ''quote (cons 'prog Prg)) ) ) ) ) ) L ) ) - lazy : (nil (setq A (lazy (prinl Computing...) 42))) - NIL : (A) Computing... - 42 : (A) - 42 : A - (NIL '42) Cheers, José -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: returning multiple distinct closures
Hi José, I've been thinking on the problem a bit and found another way to tackle it, using this incredibly *UGLY* function (all of them formatted as the output of 'pp, I have no idea how to make it more aesthetically pleasing): Me neither ;-) (de lazy Prg (let L (box (cons)) (con (val L) (list (list 'cdar (list 'con L (list 'list (list 'cons ''quote (cons 'prog Prg)) ) ) ) ) ) (val L) ) ) ... As you can see, the resulting lambda modifies itself to become just the quoted result on the first call. The way 'lazy works is by first boxing a cons pair to form the head of the lambda expression. Then it concatenates a function body to that head that is itself a call to 'con to replace itself with the computed result in a quote. For a general-use 'lazy' functionn, I would use the one from the RosettaCode task http://rosettacode.org/wiki/Formal_power_series#PicoLisp It simply uses the 'cache' function which is intended for such purposes, and has the advantage in that it lets you define real lazy functions (i.e. with arguments): (de lazy Args (def (car Args) (list (cadr Args) (cons 'cache (lit (cons)) (list 'pack (list 'char (list 'hash (caadr Args))) (caadr Args)) (cddr Args) ) ) ) ) (lazy foo () (prinl !) 2 ) : (foo) ! - 2 : (foo) - 2 : (lazy bar (X Y) (prinl !!) (+ X Y) ) - bar : (bar 2 3) !! - 5 : (bar 3 4) !! - 7 : (bar 2 3) - 5 : (bar 3 4) - 7 Cheers, - Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: closures
Hi Alex, (let @S '((I . 0)) (def 'count (curry (@S) () (job '@S (inc 'I (def 'reset (curry (@S) () (job '@S (zero I ) (let @S (list (cons 'I 0)) (let I (cons 0) I like it this way, thanks. I also found that once the things inside the closures get complicated, it might be worth using objects to get better code factoring: (class +Counter) # i (dm T () (=: i 0)) (dm count () (inc (:: i))) (dm reset () (=: i 0)) (let @C (list (cons 'C (new '(+Counter (def 'count (curry (@C) () (job '@C (count C (def 'reset (curry (@C) () (job '@C (reset C ) Or using objects directly so that I can have many independent counters... It did the job for my understanding of closures in picoLisp, I hope:-) Sometimes non-evaluating functions are a little more convenient, and at least theoretically more efficient. (zero A) occupies two cells. (zero 'A) would be three, and that's the same as (setq A 0), so it would not save any space. Have you measured and/or noticed impact on performance of these micro-optimizations? I mean, are they really worth it? Thanks, Tomas -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
closures
Hi Alex, is there a better way of achieving the following? (let @S '((I . 0)) (def 'count (fill '(() (job '@S (inc 'I) (def 'reset (fill '(() (job '@S (zero I)) The two functions are closed over the same var/env. (count) = 1 (count) = 2 (reset) = 0 (count) = 1 http://www.software-lab.de/faq.html#closures discusses curry function which allows closure inside a single function only. Thank you, Tomas -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]