Arc Forumnew | comments | leaders | submitlogin
1 point by parenthesis 5932 days ago | link | parent

A bit ugly:

  ;tail recursive, trickery to avoid reversing acc
  (def range (start end (o step (if (< end start) -1 1)))
    (= step (- step)
       end (+ end (mod (- start end) step)))
    ((afn (end acc)
       (if (or (and (< 0 step)
                    (<= end start))
               (and (< step 0)
                    (<= start end)))
           (self (+ end step) (cons end acc))
           acc))
     end nil))


  ;iterative
  (def range (start end (o step (if (< start end) 1 -1)))
    (let result nil
      (repeat (+ (truncate (/ (- end start)
                              step))
                 1)
        (push start result)
        (++ start step))
      (rev result)))


1 point by greatness 5931 days ago | link

A little prettier perhaps, though follows the same idea:

  (def range (st en (o step 1))
    (if (is step 0) (= step 1) (zap abs step))
    (let (stp-fn test) (if (> st en) `(,- ,<) `(,+ ,>))
       ((afn (i accum)
          (if (test i en) (rev accum)
                          (self (stp-fn i step) (push i accum))))
        st nil)))
If what order you want the range doesn't matter, you can remove the (rev accum) and replace it with accum. Example output:

  arc> (range 0 -5)
  (0 -1 -2 -3 -4 -5)
  arc> (range 5 5)
  (5)
  arc> (range 0 5)
  (0 1 2 3 4 5)
  arc> (range 0 10 2)
  (0 2 4 6 8 10)
  arc> (range 10 0 2)
  (10 8 6 4 2 0)
EDIT: added some error-checking, changing a step from 0 to 1 probably isn't the right thing to do, but I didn't feel like figuring out how to throw an error.

-----

1 point by greatness 5931 days ago | link

Turns out consing up the list is faster, though without the rev function it is very close:

  (def range (st en (o step 1))
    (if (is step 0) (= step 1) (zap abs step))
      (let (stp-fn test) (if (> st en) `(,- ,<) `(,+ ,>))
        ((afn (i)
           (if (test i en) nil
                           (cons i (self (stp-fn i step)))))
         st)))
though I don't know why.

-----

1 point by joseph 5930 days ago | link

How about a default start of 0?

  (def range (default (o end) (o step 1))
    (with (st (if end default 0)
           en (if end end default))
      (if (is step 0) (= step 1) (zap abs step))
      (let (stp-fn test) (if (> st en) `(,- ,<) `(,+ ,>))
         ((afn (i accum)
            (if (test i en) (rev accum)
                            (self (stp-fn i step) (push i accum))))
          st nil))))

-----