宏将模式和结果传递给core.match / match作为向量

时间:2016-05-15 15:53:28

标签: clojure macros core.match

我正在努力构建一个允许我以向量的形式将模式和结果传递给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

2 个答案:

答案 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