Question

I've been trying to get this to work with quote, quote-splicing, eval, and whatever else I can think of, but no luck so far. I understand why it doesn't work - it's being seen as a map, and it's trying to eval a, b, and c - just not how to get around it.

(def destructor {a :a b :b c :c})
; CompilerException java.lang.RuntimeException: Unable to resolve symbol: a in this context, compiling:(:1:15)

(let [destructor my-map]
  'etc)

I have a rather involved destructuring map that I'm considering using several times, so it seemed a good idea to tuck it away somewhere. Maybe there are better ways to go about it?

Était-ce utile?

La solution

Good idea, but you can't do it in quite this way, because the thing you want to store is not really a value, so you can't store it in a var.

Instead, you can define a macro that includes this in its expansion:

(defmacro with-abc [abc & body]
  `(let [~'{:keys [a b c]} ~abc]
     ~@body))

(with-abc foo
  (...use a, b, and c...))

Autres conseils

Something like @amalloy's answer was my first instinct too and it's probably the way to go. That said, it might be worth considering a plain ol' higher-order function:

(defn destruct
  [{a :a b :b c :c} f]
  (f a b c))

(destruct my-map
          (fn [a b c]
            (println a)
            (println b)
            (println c)))

It's a little nosier and you're forced to name the bindings every time, but you avoid potential hygiene issues and, depending on your level of comfort with metaprogramming, it's a little easier to put together.

You'll need to quote the destructing pattern

(def my-destructor '{a :a b :b c :c})

You can do this with levels of quoting/unquoting, but it is easier to see with a little helper function.

(defn- with-destructor* [binding & body] 
  `(let ~binding ~@body))

This eval occurs at "compile" time (during macro expansion)

(defmacro with-destructor [[destructor form] & body] 
  (eval `(with-destructor* [~destructor '~form] '~@body)))

As shown

(macroexpand-1 '(with-destructor [my-destructor {:a 1 :c 3}] (+ a c)))
;=> (clojure.core/let [{a :a, b :b, c :c} {:a 1, :c 3}] (+ a c))

Result

(with-destructor [my-destructor {:a 1 :c 3}] (+ a c))
;=> 4
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top