Arc Forumnew | comments | leaders | submitlogin
2 points by thaddeus 5677 days ago | link | parent

This will work:

    (mac forstep (v start end step . body)
        (w/uniq (gi gm)
	    (case (isnt step 0) 
              t (if (> start end)
                    `(with (,v nil ,gi ,start ,gm (- ,end (abs ,step)))
                       (loop (set ,v ,gi) (>= (- ,v (abs ,step)) ,gm) (set ,v (- ,v (abs ,step)))
                         ,@body))
                    `(with (,v nil ,gi ,start ,gm (+ ,end (abs ,step)))
                       (loop (set ,v ,gi) (<= (+ ,v (abs ,step)) ,gm) (set ,v (+ ,v (abs ,step)))
	                ,@body)))
                      nil)))
Test cases: (some input cases are just to make sure there are no infinite runs)....

    (forstep i 5 10 1 (prn i)) 
    (forstep i 5 10 2 (prn i))
    (forstep i 10 5 2 (prn i))
    (forstep i 5 10 -2 (prn i))
    (forstep i 0 1 0 (prn i))
    (forstep i 1 0 0 (prn i))
    (forstep i -2 2 1 (prn i))
    (forstep i 2 -2 1 (prn i))
    (forstep i -4 2 2 (prn i))
    (forstep i -4 2 -2 (prn i))
    (forstep i 4 -2 -2 (prn i))
    (forstep i 4 -2 2 (prn i))

That being said, I don't understand why changing 'for' this way would create problems for you, or why you want (for i 1 0 (prn i)) to return nil.

also, I still think it would be nice for arc to support keyword arguments (hint, hint pg - though he's probably not reading this), then I could have 'step' as an optional arg with a default. i.e....

    (mac for (v start end (o step 1)  . body)...

    could allow:

    (for i 20 5 (prn i)) and also something like: (for i 20 5 step:2 (prn i))
T.


1 point by skenney26 5675 days ago | link

Here's an alternative version of a step macro:

  (mac step (v init end by . body)
    (w/uniq (gi ge gtest gupdate)
     `(withs (,v nil ,gi ,init ,ge ,end
              ,gtest   (if (< ,gi ,ge) <= >=)
              ,gupdate (if (< ,gi ,ge) + -))
        (loop (set ,v ,gi)
              (,gtest ,v ,ge)
              (set ,v (,gupdate ,v ,by))
          ,@body))))

-----

1 point by thaddeus 5675 days ago | link

A much better alternate version too. The redundant code in my hacked version was obvious and ugly, but I struggled reducing it to a simpler form... Thanks!

I made a few slight adjustments though, as it failed 2 of my test cases (however unlikely they are to occur, infinite runs scare me).

    (mac step (v init end by . body)
     (if (isnt by 0) 
       (w/uniq (gi ge gtest gupdate)
        `(withs (,v nil ,gi ,init ,ge ,end
                 ,gtest   (if (< ,gi ,ge) <= >=)
                 ,gupdate (if (< ,gi ,ge) + -))
           (loop (set ,v ,gi)
                 (,gtest ,v ,ge)
                 (set ,v (,gupdate ,v (abs ,by)))
             ,@body))) nil ))
now passes these two test cases:

    (step i 5 10 -2 (prn i))
    (step i 0 1 0 (prn i))
Thanks! T.

-----

1 point by CatDancer 5677 days ago | link

That being said, I don't understand why changing 'for' this way would create problems for you

Perhaps I'm doing i from 1 to the number of things I have, and sometimes I have zero things.

Actually though it was a bit silly of me to suggest "forstep" when your version of "for" was doing what you wanted it to do. It's not a version that I'd want to use in my code, but that's no reason for you not to have your version.

-----

1 point by thaddeus 5677 days ago | link

ahh, I see. gotcha. T.

-----