Arc Forumnew | comments | leaders | submitlogin
5 points by fallintothis 5010 days ago | link | parent

Looks good. That's what I would've done, if you hadn't beaten me to it. :)

Relevant arc.arc definitions:

  (mac point (name . body)
    (w/uniq (g p)
      `(ccc (fn (,g)
              (let ,name (fn ((o ,p)) (,g ,p))
                ,@body)))))

  (mac catch body
    `(point throw ,@body))
Thus,

  (catch
    (while t
      (throw 5)))
expands into

  (point throw
    (while t
      (throw 5)))
which expands (modulo gensyms) into

  (ccc (fn (current-continuation)
         (let throw (fn ((o return-val)) (current-continuation return-val))
           (while t
             (throw 5)))))
So throw serves to "point back" to the current continuation, and optionally continues with a return value. (This seems to be the behavior of a simple (ccc (throw) ...) without the let; I'm not sure why it's defined this way.) The above loop returns 5 -- the continuation captured by ccc is outside of the loop, so its action is to return whatever value we say the while expression returns and continue evaluating anything after it.

This way, Arc gives you a decorator for return values. You can use this pattern to decorate any portion of your loop, to give different effects. Outside of the loop, it's like a break. Inside of the loop, it's like a continue due to how while is expanded.

  arc> (load "macdebug.arc") ; see http://www.arclanguage.org/item?id=11806
  nil
  arc> (macsteps '(while test
                    (point continue body1 body2 body3))
                 'show 'while 'point)
  Showing only: while, point

  Expression:

    (while test
      (point continue body1 body2 body3))

  Macro Expansion:

      (while test
        (point continue body1 body2 body3))

  ==> ((rfn gs2027 (gs2028)
         (when gs2028
           (point continue body1 body2 body3)
           (gs2027 test)))
       test)

  Expression:

    ((rfn gs2027 (gs2028)
       (when gs2028
         (point continue body1 body2 body3)
         (gs2027 test)))
     test)

  Macro Expansion:

      (point continue body1 body2 body3)

  ==> (ccc (fn (gs2029)
             (let continue (fn ((o gs2030)) (gs2029 gs2030))
               body1
               body2
               body3)))

  Expression:

    ((rfn gs2027 (gs2028)
       (when gs2028
         (ccc (fn (gs2029)
                (let continue (fn ((o gs2030)) (gs2029 gs2030))
                  body1
                  body2
                  body3)))
         (gs2027 test)))
     test)

  nil
As you can see, the continuation is captured around the body, but the test properly resides outside of the body, so it'll still be executed even if you continue (because, again, the default continuation is to keep on chuggin' along).

You could have a while macro encapsulate these (similar to catch) so you don't have to write

  (point break
    (while test
      (point continue
        body)))
I've been trying to think of good names for such a loop. The most descriptive words are long (e.g., continuable-while, breakable-while), but we usually recognize "esc" as "escape", so it's a short yet descriptive option. Something like

  (mac esc-while (test . body)
    `(point break (while ,test (point continue ,@body))))
or, crafting a portmanteau à la whilet,

  (mac whilesc (test . body)
    `(point break (while ,test (point continue ,@body))))
Don't know if this actually made continuations any clearer, but there you go.