"let ,gs ,s" frequently prevents double-evaluation of 's at run-time. It seems dumb at first when the expansion of 's is just another symbol or literal, but if 's is a more complex expression, better evaluate it just once.
(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.