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

Reply via email to