问题描述
(defmacro action1 [] `(prn "action1" ~'start ~'etype1))
(defmacro block [bindings & body]
`(let [~@(mapcat (fn [[k v]] [(if (symbol? k) k (symbol (name k))) `'~v]) (cond
(map? bindings) bindings
(symbol? bindings) (var-get (resolve bindings))
:else (throw (Exception. "bindings must be map or symbol"))))]
~body))
(defmacro bar [ctx arity & expr]
`(let [~'t1 "lv" ~'np (prn "bar_1st_let" '~ctx ~ctx '~arity ~arity '~arity(resolve (first '~arity)) )
]
(block ~ctx ;;~ctx = {start "s1" top "x"}
(fn '~arity ;; '~arity = [etype1 cid1 id1 pl1]
(let [~'__execonceresult 1]
(do ~@expr)
)
)
)
)
)
(defmacro foo_multi [metadata ctxv aritym & expr]
`(let [~@(mapcat (fn [[k v]] [k `~v]) metadata) ~'np (prn "foo_multi_1st_let" '~aritym)]
(fn ~aritym
(for [~'ctx (filter #(= (% (some (fn [~'m] (if (= (name ~'m) "top") ~'m)) (keys %))) ~'etype) '~ctxv)]
(do (prn "foo_multi_b4_case" ~'ctx ~'etype ~aritym)
(case ~'etype
"x"
(let [[~'etype1 ~'cid1 ~'id1 ~'pl1] ~aritym ~'np (prn "foo_multi_2nd_let" ~'ctx ~'etype1 ~'cid1 ~'id1 ~'pl1)]
(bar ~'ctx [~'etype1 ~'cid1 ~'id1 ~'pl1] ~@expr))
"y"
(let [[~'etype2 ~'cid2 ~'id2 ~'pl2] ~aritym]
(bar ~'ctx [~'etype2 ~'cid2 ~'id2 ~'pl2] ~@expr))
))))))
(def foo (foo_multi { meta1 "m1" meta2 "m2" } [{start "s1" top "x"}
{start "s3" top "x"} {start "s2" top "y"}] [etype a1 a2 a3] (block {toc "c"}
(block {c1 "d"} (action1)) "end"))
)
(let [myarr ["x" 100 200 {"p" 1 "q" 2}]] (apply foo myarr))
无法将条形从bar宏传递到block宏,并获得 java.lang.NullPointerException
。
如果我注释了来自bar宏的块调用,则会执行其余代码。
Unable to pass arity from bar macro to block macro and getting java.lang.NullPointerException
.The rest of the code executes if I comment the block call from the bar macro.
(defmacro bar [ctx arity & expr]
`(let [~'t1 "lv" ~'np (prn "bar_1st_let" '~ctx ~ctx '~arity ~arity '~arity(resolve (first '~arity)) )
]
(comment block ~ctx ;;~ctx = {start "s1" top "x"}
(fn '~arity ;; etype specific ~arity eg: [etype1 cid1 id1 pl1]
(let [~'__execonceresult 1]
(do ~@expr) ;; uses etype1
)
)
)
)
)
下面的注释是调试行的输出:
After commenting below is the output of the debug lines :
"foo_multi_1st_let" [etype a1 a2 a3]
"foo_multi_b4_case" {start "s1", top "x"} "x" ["x" 100 200 {"p" 1, "q" 2}]
"foo_multi_2nd_let" {start "s1", top "x"} "x" 100 200 {"p" 1, "q" 2}
"bar_1st_let" ctx {start "s1", top "x"} [etype1 cid1 id1 pl1] ["x" 100 200 {"p" 1, "q" 2}] [etype1 cid1 id1 pl1] nil
"foo_multi_b4_case" {start "s3", top "x"} "x" ["x" 100 200 {"p" 1, "q" 2}]
"foo_multi_2nd_let" {start "s3", top "x"} "x" 100 200 {"p" 1, "q" 2}
"bar_1st_let" ctx {start "s3", top "x"} [etype1 cid1 id1 pl1] ["x" 100 200 {"p" 1, "q" 2}] [etype1 cid1 id1 pl1] nil
根据上面打印的调试行,在bar宏中,我无法解决第一个arity符号,并且将其打印为nil(不知道原因)。目标是将arity正确地从bar宏传递到block宏,并能够访问和打印action1宏中的start和etype1值。
As per the debug lines printed above, In the bar macro I am unable to resolve first arity symbol and it is printed nil (Don't know the reason why). The goal is to pass arity correctly from bar macro to the block macro and be able to access and print start and etype1 value in action1 macro.
推荐答案
正如@ I0st3d所指出的,这可能是修改条形定义后的解决方案,并且foo_multi会像上面的解决方案my-multi-let一样。
as @I0st3d pointed out, this could be your solution after modifing bar definition and foo_multi will become like above solution my-multi-let.
(defmacro action1 [] `(prn "action1" ~'start ~'etype))
(defn named-type? [m] (when (= (name m) "top") m))
(defmacro block [ctx & expr]
`(let [~@(mapcat (fn [[k v]] [k `~v]) ctx)] ~@expr))
(defmacro bar [bindings & body]
`(block ~bindings (if (= ~'top ~'etype) (do
~@body))))
(defmacro foo_multi [metadata bindings-list arity & body]
(let [fns (->> bindings-list
(map (fn [b] `(bar ~b ~arity ~@body))))
] `(block ~metadata (fn ~arity (do ~@fns)))
))
(def foo (foo_multi {meta1 "m1" meta2 "m2"} [{start "s1" top "x"}
{start "s2" top "y"}] [etype a1 a2 a3]
(block {toc "c"} (block {c1 "d"} (action1)) "end")
))
(let [myarr ["x" 100 200 {"p" 1 "q" 2}]] (apply foo myarr))
在bar宏中,您可以访问所有arity参数,因此,如果需要,您还可以创建针对etype特定符号而变化的map var。
您的(让[myarr [ x 100200 { p 1 q 2}]](应用foo myarr))也将按预期工作。
In bar macro you'll get all arity params accessible, so you can create a map vars varying for etype specific symbols also if required.your (let [myarr ["x" 100 200 {"p" 1 "q" 2}]] (apply foo myarr)) will also work as expected.
这篇关于Clojure宏:根据条件将过滤后的地图和Arity传递给其他宏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!