(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).
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.