(aif 9 (+ 9 %else) (+ 10 %test))
; => (if 9 (+ 9 (+ 10 9)) (+ 10 9))
"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.] (aand (+ 30 20) *1)
; => (and (+ 30 20) (+ 30 20))
(aand 1 2 "third" (aand 33 **3))
; => (and 1 2 "third" (and 33 "third"))
Utterly bonkers, and I love the hack :)-----
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.
-----
from the read-me:
"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.
-----
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).-----
(match 123
((and (? even?) it) (~a it " is even"))
(it (~a it " is odd")))
[0]: https://docs.racket-lang.org/reference/match.html -----
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:
(aif (ns-resolve *ns* 'specs)
(let [c (compile spec :name name)]
(swap! (var-get %test) update (:property c) set/union #{c}))
(do (intern *ns* 'specs (atom {}))
%then))
Would love to hear if anyone has some crazy ideas. Beyond just conditionals too.-----
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.-----
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.
-----