> On Sep 12, 2017, at 11:09 AM, Stefan Israelsson Tampe > <stefan.ita...@gmail.com> 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.