[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Chicken-users] possible lazy-let macro?
From: |
Daishi Kato |
Subject: |
Re: [Chicken-users] possible lazy-let macro? |
Date: |
Thu, 17 Nov 2005 21:17:54 +0900 |
User-agent: |
Wanderlust/2.15.1 (Almost Unreal) Emacs/21.4 Mule/5.0 (SAKAKI) |
Hi!
Nice to know of identifier-syntax.
It looks useful once you understand how it works.
I also found it is faster than delay/force,
the functions are different though.
Well, nonetheless, there still are some overheads,
assigning variables, and cheking them if they are new.
What I want is no overhead, so that I can basically
replace all let with lazy-let, unless there is a side-effect.
Here is my solution, I hope someone review it.
(use srfi-1)
(define-macro (lazy-let vars . body)
(let loop ([names (map car vars)] [xpr (cons 'begin body)])
(cond
((list? xpr)
(let* ([flat (map flatten xpr)]
[cnt (lambda (x)
(length (filter (lambda (y) (memq x y)) flat)))])
(let-values ([(nms1 nms2)
(partition (lambda (x) (> (cnt x) 1)) names)])
(if (null? nms1)
(map (lambda (x) (loop names x)) xpr)
`(let ,(filter (lambda (x) (memq (car x) nms1)) vars)
,(map (lambda (x) (loop nms2 x)) xpr))))))
((and (symbol? xpr) (memq xpr names))
(cadr (assq xpr vars)))
(else
xpr))))
Note:
- not tested much
- not sure if there are any restrictions
- macro expanding may be costly, could be improved?
Daishi
At Wed, 16 Nov 2005 20:11:15 -0600,
Alex Shinn wrote:
>
> At Wed, 16 Nov 2005 18:18:00 +0900, Daishi Kato wrote:
> >
> > Does anyone know of any existence of a lazy-let macro,
> > which does the following?
> >
> > <convert from>
> >
> [...]
> >
> > (lazy-let ([a (get-a)][b (get-b)])
> > (if (condition)
> > (begin (display a) a)
> > (begin (display b) b)))
> >
> > <into>
> >
> > (if (condition)
> > (let ([a (get-a)]) (begin (display a) a))
> > (let ([b (get-b)]) (begin (display b) b)))
>
> This is sort of thing identifier-syntax was made for. Basically,
>
> (require-extension syntax-case)
>
> (define-syntax foo (identifier-syntax bar))
>
> replaces the symbol foo everywhere with bar (which can be any
> expression). There's also a form
>
> (identifier-syntax (id1 tmpl1) ((set! id2 e2) tmpl2))
>
> which let's you specify what happens when the variable is set (id1 and
> id2 are dummy symbols for the sake of pattern matching). Thus the
> example given in the manual shows how to conceptually treat a symbol
> as the car of a list:
>
> (let ([x (list 0)])
> (define-syntax car-x
> (identifier-syntax
> (id (car x))
> ((set! id e) (set-car! x e))))
> (let ([before car-x])
> (set! car-x 1)
> (list before car-x x)))
> => (0 1 (1))
>
> Replacing a with (get-a) everywhere is thus trivial, but to only
> compute (get-a) once we need to check if it has already been computed.
> The implementation below stores the result in a temp variable (which
> is also used to allow setting a):
>
> ;; using define-macro since syntax-case is so ugly
> (define-macro (lazy-let params . body)
> (append (list 'lazy-let-with-temp-ids)
> (list (map (lambda (x) (append x (list (gensym)))) params))
> body))
>
> ;; same lazy-let but of the form (lazy-let ((var val tmp) ...) . body)
> ;; so that we have a unique temp-var per var to store the values
> (define-syntax lazy-let-with-temp-ids
> (syntax-rules ()
> ((lazy-let ((var val tmp) ...) . body)
> (let ((undef (list 'undef)))
> (let ((tmp undef) ...)
> (let-syntax
> ((var (identifier-syntax
> (id (begin
> (if (eq? tmp undef)
> (set! tmp val))
> tmp))
> ((set! id e) (set! tmp e))))
> ...)
> . body))))))
>
> ;; some definitions to use the example as-is:
> (define (condition) (zero? (random 2)))
> (define (get-a) (print "getting a") 'a-val)
> (define (get-b) (print "getting b") 'b-val)
>
> ;; works as expected:
> #;7> (lazy-let ([a (get-a)][b (get-b)])
> (if (condition)
> (begin (print a) a)
> (begin (print b) b)))
> getting a
> a-val
> a-val
>
> ;; we can also set the lazy variables
> #;8> (lazy-let ([a (get-a)][b (get-b)])
> (if (condition)
> (begin (print a) (set! a 'new-a-val) a)
> (begin (print b) (set! b 'new-b-val) b)))
> getting a
> a-val
> new-a-val
>
>
> --
> Alex
- [Chicken-users] possible lazy-let macro?, Daishi Kato, 2005/11/16
- Re: [Chicken-users] possible lazy-let macro?, Thomas Chust, 2005/11/16
- Re: [Chicken-users] possible lazy-let macro?, Alex Shinn, 2005/11/16
- Re: [Chicken-users] possible lazy-let macro?,
Daishi Kato <=
- Re: [Chicken-users] possible lazy-let macro?, Thomas Chust, 2005/11/17
- Re: [Chicken-users] possible lazy-let macro?, Daishi Kato, 2005/11/17
- Re: [Chicken-users] possible lazy-let macro?, Thomas Chust, 2005/11/17
- Re: [Chicken-users] possible lazy-let macro?, Alex Shinn, 2005/11/17
- Re: [Chicken-users] possible lazy-let macro?, Daishi Kato, 2005/11/17