Skip to content

Instantly share code, notes, and snippets.

@rauhs
Created August 22, 2015 22:04
Show Gist options
  • Save rauhs/909d1af8f4ac1dc73e21 to your computer and use it in GitHub Desktop.
Save rauhs/909d1af8f4ac1dc73e21 to your computer and use it in GitHub Desktop.
Macro: Assoc a map only if the key is nil. Does NOT evaluate the value unless it is nil.
(defmacro assoc-if-nil
"Takes a map as the first argument and a succession of key value pairs that
are used to set the key to value if the key of the map is nil. The value part
is only evaluated if the key is nil (thus different semantics to (merge)).
Example:
(assoc-if-nil {:a {:b :set}}
[:a :b] :non-def
[:a :c] :non-def
:d :non-def)
;; =>{:a {:b :set, :c :non-def}, :d :non-def}"
[m & clauses]
(assert (even? (count clauses)))
(let [g (gensym)
get-fn (fn[kork] (if (vector? kork) `get-in `get))
assoc-fn (fn[kork] (if (vector? kork) `assoc-in `assoc))
pstep (fn [[kork v]] `(if (~(get-fn kork) ~g ~kork)
~g
(~(assoc-fn kork) ~g ~kork ~v)))]
`(let [~g ~m ;; avoid double evaluation
~@(interleave (repeat g) (map pstep (partition 2 clauses)))]
~g)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment