5

我一直试图让它与引用、引用拼接、评估以及我能想到的任何其他东西一起使用,但到目前为止还没有运气。我理解为什么它不起作用 - 它被视为一张地图,它正在尝试评估a,bc- 只是不知道如何绕过它。

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

我有一个相当复杂的解构地图,我正在考虑多次使用它,所以把它藏在某个地方似乎是个好主意。也许有更好的方法来解决它?

4

3 回答 3

3

好主意,但你不能完全这样,因为你想要存储的东西并不是一个真正的值,所以你不能把它存储在一个 var 中。

相反,您可以定义一个在其扩展中包含此内容的宏:

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

(with-abc foo
  (...use a, b, and c...))
于 2014-05-14T02:46:37.517 回答
2

@amalloy 的回答之类的东西也是我的第一直觉,这可能是要走的路。也就是说,可能值得考虑一个普通的高阶函数:

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

它有点吵,你每次都被迫命名绑定,但你避免了潜在的卫生问题,并且根据你对元编程的舒适程度,它更容易组合起来。

于 2014-05-14T03:12:09.007 回答
0

您需要引用破坏模式

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

您可以使用引用/取消引用的级别来执行此操作,但使用一些辅助功能更容易看到。

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

eval发生在“编译”时(在宏扩展期间)

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

如图所示

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

结果

(with-destructor [my-destructor {:a 1 :c 3}] (+ a c))
;=> 4
于 2014-05-14T17:03:46.170 回答