Arc Forumnew | comments | leaders | submitlogin
2 points by evanrmurphy 5211 days ago | link | parent

One way to do it would be with macro-generating macros. Take loop for example. arc.arc defines loop as follows:

  (mac loop (start test update . body)
    (w/uniq (gfn gparm)
      `(do ,start
           ((rfn ,gfn (,gparm) 
              (if ,gparm
                  (do ,@body ,update (,gfn ,test))))
            ,test))))
Here's how you could write aloop, which is just like loop except that it grants access to itself through the generated macro continue:

  (mac aloop (start test update . body)
    (w/uniq (gfn gparm)
      (mac continue ()
        `(do ,update (,gfn ,test)))
      `(do ,start
           ((rfn ,gfn (,gparm) 
              (if ,gparm
                  (do ,@body (continue))))
            ,test))))
Let's go ahead and define afor because it will be less awkward to demo with:

   ; s/loop/aloop/ was the only change from for's definition
  (mac afor (v init max . body)
    (w/uniq (gi gm)
      `(with (,v nil ,gi ,init ,gm (+ ,max 1))
         (aloop (assign ,v ,gi) (< ,v ,gm) (assign ,v (+ ,v 1))
           ,@body))))
And now check it out!

  ; prints i from zero to ten, skipping odd values of i
  arc> (afor i 0 10
         (if (odd i)
              (continue)
             (pr i)))
  *** redefining continue
  0246810nil
(Note that since the continue macro gets generated anew on each call to aloop, you'll get the "redefining continue" message every time you call aloop or afor.) You could use the above definitions to spin off labeled versions of down, forlen, each and on, and a similar technique could be applied to redefine the while-family of macros.


2 points by rocketnia 5211 days ago | link

Defining macros during macro-expansion strikes me as being a bit error-prone, and here's one concern:

  (afor i 0 10
    (afor j 0 10
      ...
      (continue)
      ...
      )
    ...
    (continue)
    ...
    )
I'm pretty sure the second (continue) form is expanded after the inner (afor ...) form is expanded, so that it tries to continue the wrong loop, but ends up referring to an unbound variable instead.

I recommend sticking to an anaphoric variable that has no macro wrapping it, sort of like this:

  (mac aloop (start test update . body)
    (w/uniq (gfn gparm)
      `(do ,start
           ((rfn ,gfn (,gparm) 
              (if ,gparm
                  (let continue (fn () ,update (,gfn ,test))
                    ,@body
                    (do.continue))))
            ,test))))

-----

1 point by evanrmurphy 5210 days ago | link

I'm pretty sure the second (continue) form is expanded after the inner (afor ...) form is expanded, so that it tries to continue the wrong loop, but ends up referring to an unbound variable instead.

Very good point, I hadn't tried to nest them before.

I will try your aloop definition when I get the chance.

-----

2 points by garply 5210 days ago | link

Your code works because nothing follows your continue. This does not work as I would want it to:

(afor i 0 3 (when (odd i) (continue)) (prn i)) goes to:

0

2

4

5

nil

-----