Arc Forumnew | comments | leaders | submitlogin
"while" with terminal test...
4 points by drcode 6092 days ago | 8 comments
Hi everyone- here's a super easy question for you...

As you probably know, the "while" macro checks a condition and then executes a body- then repeats the process.

I often need the common variant where the test happens _after_ the body is evaluated... It would be trivially to write as a macro, but certainly this must be so common that there's an easy way to do this already?

I can't find such a variant anywhere in the docs. (Unfortunately the function "until" isn't it, despite the promising name) Most languages define such a variant as part of the language.

I'm sure there's an obvious answer to my question- Anyone mind helping me out? Thanks!



3 points by drcode 6091 days ago | link

I found the probably best way to do this in arc (a "while" loop with the condition after the body)

the trick is to use the "drain" command and have your expression return t/nil to indicate whether the calculation should repeat.

-----

1 point by Jesin 6086 days ago | link

I looked at arc.arc, and since this is the definition of while:

  (mac while (test . body)
    (w/uniq (gf gp)
      `((rfn ,gf (,gp)
          (when ,gp ,@body (,gf ,test)))
        ,test)))
I figured this would work for dowhile:

  (mac dowhile (test . body)
    (w/uniq (gf gp)
      `((rfn ,gf (,gp)
          (when ,gp ,@body (,gf ,test)))
        t)))
I just replaced the first test that would be evaluated with t, while leaving subsequent tests alone. But yes, I agree that it's strange that Arc has until but not dowhile.

-----

1 point by stefano 6092 days ago | link

(mac dowhile (test . body) (w/uniq (f) `(rfn ,f () ,@body (if ,test (,f)))))

Should work(haven't tested it yet).

-----

1 point by almkglor 6092 days ago | link

Here's a better version which puts the test at the end:

  (mac dowhile body
    (with (rbody (cut body 0 -1)
           test (last))
      (w/uniq f
        `(rfn ,f ()
          ,@body
          (if ,test (,f))))))

-----

3 points by drcode 6091 days ago | link

Thanks guys- Sounds like noone else knows of a way to do this with the current libraries either. Now I know I didn't just miss this feature somehow.

-----

1 point by tokipin 6090 days ago | link

i would use something like (based on the rfn idea):

  (= a 0)
  
  ((afn ()
     (pr ++.a)
     (if (isnt a 8) (self))))

-----

3 points by drcode 6089 days ago | link

right- as I mentioned in the other comment, this is less cumbersome with "drain"

  (= a 0)
  
  (drain (do (pr ++.a)
             (isnt a 8)))

-----

3 points by almkglor 6088 days ago | link

shorter thus:

  (drain:do
    (pr ++.a)
    (isnt a 8))

-----