Pregunta

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?

¿Fue útil?

Solución

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

Otros consejos

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top