[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: macro helpers
From: |
Matt Wette |
Subject: |
Re: macro helpers |
Date: |
Tue, 12 Sep 2017 18:10:01 -0700 |
> On Sep 12, 2017, at 11:09 AM, Stefan Israelsson Tampe <address@hidden> wrote:
>
> Writing efficient macros is a bit difficult. Let me explain by using an
> example. The background
> is that I maintaining a python compiler and python like object system and
> would like to program
> a scheme macro that would be the scheme counterpart to various python
> construct. For fun
> consider pythons for loop. it's looping depending on iterators and have break
> and continue.
>
> Here is a hypothetical for loop:
>
> (for lp ((x : I)) ((c 1))
> (lp #:continue (+ x c))
>
> #:final
> c)
>
> The python iterators signals the end of the loop with raising en exception
> which is not too costly and we will return the #:final as a value at that
> point. This is a mix of scheme and python. Now what we
> can do further is to introduce break,continue and break and final as
>
> (lp #:continue c) e.g. continue with c
> (lp #:break c) e.g. break with c
> (lp #:final) e.g. execute final with current c
>
> This has a great potential of a easy generalization of python for loops an
> implementation could be like, its very slow though, here is a take on the
> implementation which describes the macro
> (more work is needed, not a propper pattern here)
>
> (define-syntax for
> (lambda (x)
> (syntax-case x ()
> ((for lp ((x ... : E) ... (c n) ...) code ... #:final fin ...)
> (with-syntax (((It ...) (generate-temporaries #'(O ...)))
> ((cc ...) (generate-temporaries #'(c ...)))
> (((x1 ...) ...) (generate-temporaries #'((x ...) ...)))
> (((x2 ...) ...) (generate-temporaries #'((x ...) ...))))
> #'(let ((It E) ... (c n) ... (x 'None) ... ...)
> (let/ec lp-break
> (catch IteratorException
> (lambda ()
> (letrec ((enclosing
> (lambda (cc ...)
> (set! c cc) ...
> (call-with-values
> (lambda () (next It))
> (lambda (x2 ...)
> (set! x1 x2) ...))
> ...
> (set! x x1)
> ... ...
> (call-with-values
> (lambda ()
> (let/ec lp-continue
> (define (lp tag . args)
> (cond
> ((eq? tag #:continue)
> (apply lp-continue args))
> ((eq? tag #:break)
> (apply lp-break args))
> ((eq? tag #:final)
> (lp-continuation #:final))))
> code ...))))
> (lambda args
> (if (eq? (car args) #:final)
> (throw IteratorException)
> (apply enclosing (cdr args))))))))
> (enclosing c ...)))
> (lambda q fin ...)))))))))
>
> The value of tail position is transfered to the next iteration of the loop.
> It's not functional. But this is for the full featured version in which lp
> may be transferred to another function and there inside a loop called e.g.all
> crazy things, the easy steps would be to have full control in multiple loops.
> Note how this enables great refactoring of functions with many loops inside
> loops. Anyway for normal loops this is really really slow, and one would
> really like to have streamlined code when (lp #:continue ...) is used at tail
> positions and for cases where we can prove that lp is never used in any
> advanced configuration, we would like to know if lp, (lp #:continue ..) (in
> tail position) and finally if (lp #:break ...) is used or not. But how to do
> this at the macro level? I don't think that we
> have any good history of optimizing this case!
>
> WDYT
I don't quite understand why this is a macro issue. Is there efficient code,
in this patterh, you could
write by hand that is not done by macro? My guess is you are looking for a
clean pattern for efficient
execution of python for-loops. Why not start with a list of possible
implementations, try them out, and
then work to develop your syntax-pattern? You could try prompts or
continuations maybe. I make :( when
I see set! in your pattern, BTW.
Matt
CC to guile-user as this may be of interest there.