我正在努力构建一个允许我以向量的形式将模式和结果传递给core.match/match
的宏。我希望能够做到这一点:
(let [x {:a 1}
patterns [[{:a 2}] :high
[{:a 1}] :low]]
(my-match x patterns))
> :low
我尝试了以下和其他一些不起作用的方法,除非我将模式作为文字传递。
(defmacro my-match [e ems]
`(m/match [~e] ~@ems))
(let [x {:a 1}
patterns [[{:a 2}] :high
[{:a 1}] :low]]
(my-match x patterns))
=> CompilerException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol, compiling:(*cider-repl kontrakt*:106:10)
(let [x {:a 1}]
(my-match x [[{:a 2}] :high
[{:a 1}] :low]))
=> :low
答案 0 :(得分:2)
宏在编译时扩展,因此在扩展期间不能依赖运行时信息(参数的值)。根本问题是您不能以与应用函数相同的方式应用宏。
In clojure, how to apply a macro to a list?
所以你必须要求使用eval:
(defmacro functionize [macro]
`(fn [& args#] (eval (cons '~macro args#))))
(defmacro my-match [e ems]
`(apply (functionize m/match) [~e] ~ems))
或者以不同的方式处理问题(执行运行时模式匹配而不是编译时模式匹配)。
答案 1 :(得分:1)
解决问题的最简单方法是使用普通的旧地图:
(ns clj.core
(:use tupelo.core))
(def x {:a 1} )
(def patterns { {:a 2} :high
{:a 1} :low } )
(spyx (get patterns x))
;=> (get patterns x) => :low
由于您没有"通配符值",您根本不需要core.match
。如果您希望匹配外卡值,请参阅功能wild-match?
in the Tupelo library.示例:
(wild-match? {:a :* :b 2}
{:a 1 :b 2}) ;=> true
(wild-match? [1 :* 3]
[1 2 3]
[1 9 3] )) ;=> true
(wild-match? {:a :* :b 2}
{:a [1 2 3] :b 2}) ;=> true