Extensible macros (A flatter cond follow-up)

unsorted — cgrand, 21 September 2012 @ 8 h 51 min

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

3 Comments »

  1. 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!

    Comment by Mark Engelberg — 21 September 2012 @ 9 h 55 min
  2. Christophe,

    Wow. This looks really cool. I’ve wanted something like this many times! I’ll try it out.

    Thanks!
    Eric

    Comment by Eric Normand — 22 September 2012 @ 3 h 07 min
  3. Good answers in return of this difficulty with real arguments and explaining all regarding that.

    Comment by rightproxy — 29 June 2013 @ 13 h 58 min

RSS feed for comments on this post. TrackBack URI

Leave a comment

(c) 2024 Clojure and me | powered by WordPress with Barecity