Extensible macros (A flatter cond follow-up)
I pushed Utils out. It features reduce-by
but also variations on cond
(the ones introduced in the comments of A Flatter Cond) and if-let
.
cond
supports the following operators: :let
, :when
, :when-let
and vectors in test position are treated as the binding form to a if-let
(thus setting the local bindings) for the “then” expression not for the rest of the cond
.
if-let
supports :let
to introduce new bindings without testing their expression for truth.
One notable twist to these macros is that thanks to net.cgrand.xmacros
they are extensible: new operators can safely be participated to the macros (proper namespacing is enforced). See the cond
implementation, abbreviated below:
(defmacro cond "An extensible variation on cond. Trailing else is supported. keywords in test position are treated as operators. Operators impls signature is [rhs else] where rhs is the \"then\" expression next to the operator." [& clauses] (when-let [[op rhs & more-clauses] (seq clauses)] (if (next clauses) (x/expand-op op rhs `(cond ~@more-clauses)) test))) (x/defdefault-op cond [test-expr then else] (if (vector? test-expr) `(if-let ~test-expr ~then ~else) `(if ~test-expr ~then ~else))) (x/defop cond :let "Introduces local bindings." [bindings cont] `(let ~bindings ~cont)) (x/defop cond :when "Short-circuits the rest of the cond if false" [test-expr cont] `(when ~test-expr ~cont)) (x/defop cond :when-let "Short-circuits the rest of the cond if false and introduces local bindings." [bindings cont] `(when-let ~bindings ~cont))
I’ve been using the “flatter cond” since you introduced it a while back, and I think it is absolutely indispensable. I want everyone to try it, love it, and clamor for its inclusion in core — it’s that good. (I have a feeling that the trailing else will have to be dropped for it to have a chance of getting included in core though.)
Why do I want it in the core? Because I use it so consistently, I don’t want to clutter my code with utils/cond and “use”ing utils requires me to specifically exclude cond, if-let, when-let from clojure.core, making it a bit more tedious to include utils liberally. (As I recall, if I don’t do the exclusion, it will issue warnings the first time I evaluate the file, but then errors the subsequent times I send it to the REPL.)
The new extensibility is a nice touch. Thanks again for introducing this. Now go out and promote it and let’s get everyone hooked!
Christophe,
Wow. This looks really cool. I’ve wanted something like this many times! I’ll try it out.
Thanks!
Eric
Good answers in return of this difficulty with real arguments and explaining all regarding that.