Arc Forumnew | comments | leaders | submitlogin
2 points by fallintothis 5599 days ago | link | parent

For example, consider defining on without it.

  (mac wrong-on (var s . body)
    (if (is var 'index)
        (err "Can't use index as first arg to on.")
        `(forlen index ,s
           (let ,var (,s index)
             ,@body))))
Then

  arc> (wrong-on x (prn "abcd") (prs index x) (prn))
  abcd
  abcd
  0 a
  abcd
  1 b
  abcd
  2 c
  abcd
  3 d
  nil
because

  (macex1 '(wrong-on x (prn "abcd") (prs index x) (prn)))
is

  (forlen index (prn "abcd")
    (let x ((prn "abcd") index)
      (prs index x) (prn)))
Notice that (prn "abcd") is evaluated once at the start, then once on each iteration.

Versus the arc.arc on:

  arc> (on x (prn "abcd") (prs index x) (prn))
  abcd
  0 a
  1 b
  2 c
  3 d
  nil
because

  (macex1 '(on x (prn "abcd") (prs index x) (prn)))
is

  (let gs1763 (prn "abcd")
    (forlen index gs1763
      (let x (gs1763 index)
        (prs index x) (prn))))
Here, (prn "abcd") is evaluated only once. It's bound to the gensym gs1763, which won't clash with any variable names you already have (not strictly, cf. http://arclanguage.org/item?id=5104, but that's the idea).

You can automate this idiom with the once-only macro; see http://arclanguage.org/item?id=9918 or towards the end of http://gigamonkeys.com/book/macros-defining-your-own.html.



1 point by akkartik 5599 days ago | link

Thanks for the pointer to once-only. Is this the version I should use? (I'm having trouble wrapping my head around the nested unquotes)

http://arclanguage.org/item?id=9939

My definition of on seems to eval the list only once anyway, but now I'm feeling paranoid about where else I've missed this and taken a performance hit.

-----

1 point by fallintothis 5599 days ago | link

Is this the version I should use?

You can if you want. It works.

  arc> (let a '(prn 5)
         (once-only (a)
           `(+ ,a 1)))
  (with (gs2595 (prn 5)) (+ gs2595 1))
Note that the parameter list doesn't work like w/uniq, where you can have a single argument with no parentheses. i.e.,

  arc> (let a '(prn 5)
         (once-only a
           `(+ ,a 1)))
  Error: "Can't take car of a"
This was fixed in the Anarki version (http://github.com/nex3/arc/blob/master/lib/util.arc#L374), but that version uses Anarki-specific utilities. The fix is still vanilla-Arc, if you want it:

  (mac once-only (names . body)
    (withs (names (check names alist (list names))
            gensyms (map1 [uniq] names))
      `(w/uniq ,gensyms
        `(with ,(list ,@(mappend list gensyms names))
          ,(with ,(mappend list names gensyms)
            ,@body)))))

  arc> (let a '(prn 5)
         (once-only a
           `(+ ,a 1)))
  (with (gs1724 (prn 5)) (+ gs1724 1))
My definition of on seems to eval the list only once anyway

Yeah, your definition's fine because each already handles the multiple-eval situation.

Side note:

  (zap [+ 1 _] index)
is equivalent to

  (zap + index 1)
which is equivalent to

  (++ index)
Just so you know.

-----

1 point by akkartik 5599 days ago | link

D'oh. You know, I actually tried (zap ++ index) first. Don't know what I was thinking.

Thanks for the (zap + index 1) trick.

-----