在创建 defmethod 方法的宏中处理析构

问题描述 投票:0回答:2

在我的用例中,我有一个带有两个参数的多方法,它们都是映射。第一个用于计算调度值等。第二个是一种上下文变量,它将被实现方法修改或未修改地返回。

(defmulti code (fn [input _] (:cmd input)))

; example implementation
(defmethod code "foo" [_ {var :var :as ctx}]
  {:out (str "foo; ctx.var=" var)
   :ctx ctx})

如您所见,在此示例实现中,我返回了未修改的上下文变量。由于我有很多不修改上下文的实现,我决定编写一个宏来为我编写 def 方法,将计算输出放在键

:out
下,将未修改的上下文放在
:ctx
下:

(defmacro stable-ctx [multifn dispatch-val args impl]
  `(defmethod ~multifn ~dispatch-val ~args
     {:out ~impl
      :ctx (second ~args)}))

这适用于以下实现:

(stable-ctx code "bar" [_ _] "bar")

(stable-ctx code "foo2" [_ ctx] (str "foo2; ctx.var=" (:var ctx)))

但是,如果我在我的定义中使用析构函数,很明显它会失败:

(stable-ctx code "foo3" [_ {var :var}] (str "foo3; ctx.var=" var))

(code {:cmd "foobar"} {:var 2})
的输出是
{:out "foobar; ctx.var=2", :ctx {2 :var}}
而不是
{:out "foobar; ctx.var=2", :ctx {:var 2}}

我想知道如何解决这个问题。我怀疑 clojure.core/destructure 函数可以帮助我解决这个问题,但遗憾的是它缺少文档。

clojure macros destructuring
2个回答
0
投票

只需为上下文参数使用不同的私有名称,以及

let
客户想要的名称。他们可以用他们的名字做任何他们想做的事,你仍然会有你的名字。

(defmacro stable-ctx [multifn dispatch-val [a b] impl]
  `(defmethod ~multifn ~dispatch-val [~a y#]
     (let [~b y#]
       {:out ~impl
        :ctx y#})))

这里

b
y#
是同一事物的两个名称,但是
y#
已知是您创建的 gensymmed 符号,因此返回是安全的。
b
是客户放入 arg 向量中的任何内容,因此如果他们愿意,可以对其进行解构。


0
投票

也许我遗漏了什么,但你总是可以将解构移动到

impl
代码中,例如:

(stable-ctx code "foo3" [args]
  (let [{var :var}  (second args)]
    (str "foo3; ctx.var=" var)))
© www.soinside.com 2019 - 2024. All rights reserved.