"In `acond`, `aif` and `awhen`, `%test` or `%t` gets replaced with the 'test' form. `%then` gets replaced by the 'then' form, and `%else` by the 'else' form."
"If nested you can access the previous level by doubling the first letter of the symbol. For example, '%ttest' would get you the previous [containing?] 'test' form, while '%eeelse' would get you the 'else' form 2 levels up. In the `aand` and `aor` macros you can reference arguments by using a symbol of form `<star><num>` where 'num' is the 1-index of the argument. Previous levels are accessed by doubling the `<star>` character. So the second 'test' form of an `aand` can by accessed with `<star>2` and the third argument of the previous [containing?] `aand` would be `<star><star>3`." [Working around the crappy pseudomarkdown here.]
Staring at these examples again, another thought occurs to me: do these macros cause multiple evaluation, or are the equivalences above just loose? Can anybody tell? I can't tell just from skimming the implementation.
If they're doing multiple evaluations they're a lot less useful than Paul Graham's original anaphoric macros even if they seem superficially more powerful/expressive.
"Note that as of right now the symbols are replaced by copying in the expression it references, not by binding to a common variable. Hence not suitable for using with expressions that cause side-effects or involve a lot of computation. That will be changed soon."
I presume, by reading this, these expressions will be evaluated each time they are triggered within the operation, so the answer is - yes they will. But, as the read-me also suggests, this is a "WORK IN PROGRESS" and the author has stated intentions to assign variables, which would solve the issue.
Saw this on reddit and given that it's derived from Arc I thought I'd post it over here.
Certainly these are much more involved than my functions. My aif for example is:
(defmacro aif [expr & body]
`(let [~'it ~expr]
(if ~'it
(do ~(first body))
(do ~@(next body)))))
Actually, when I started in Clojure I was using these anaphoric operations a lot, but most of my code has moved away from them (for no particular reason, I just haven't needed them much I guess).
Racket doesn't have anaphoric macros as part of the core language (although there is a module for that), so that's a bit difficult getting used to when coming from Arc, but I find that pattern matching[0] can be used to the same effect:
(match 123
((and (? even?) it) (~a it " is even"))
(it (~a it " is odd")))
Author here. Glad to see some interest, sometimes I lurk here and now I feel bad not having submitted here myself.
Interestingly the "%else" would actually be cataphoric, as you refer to what comes next rather than before. So "co-referential macros" would be more fitting if you want to stick with the linguistics analogy. But that'd be too exotic of a term.
And yes as akkartik notes, it causes multiple evaluations right now, mostly just laziness and indecision on my part.
I'll probably be giving control over this. Here's a real example of code where you actually want current behavior:
Thanks for that example. I see now that you mostly only need to worry about multiple evaluation for the `%test` branch; `%then` and `%else` should be exclusive anyway, and I'm not concerned about the growth in macroexpanded code when duplicating a few s-expressions.
You could still have repeated use within a '%then' or '%else' block:
(aif (test)
(something)
(do %then %then))
But it should suffice to perform one evaluation in each branch. Cool! That seems simpler than some of the alternatives I'd been thinking about. I'd try to evaluate everything ahead of time and then realize that I shouldn't run `%else` if the `%test` returns a truthy value.
Didn't consider a double `%then` or `%else`, thanks. Raises some interesting problems.
Generally the plan is to have a special character control whether it gets bound or inlined, probably `!`. So say `%test!` would get inlined like right now, while using `%test` would bind (and doing both would also be possible). But for a `%then` you'd generally only want to bind if there's 2+ so I could count usages instead.
Mostly side-effects free now, controllable via `!` as noted below (in most cases). Also added tests that compare macroexpand results where feasible. Big cleanup next.