3

我正在努力构建一个宏,让我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
4

2 回答 2

2

宏在编译时展开,因此在展开期间不能依赖运行时信息(参数的值)。根本问题是您不能以与应用函数相同的方式应用宏。

在clojure中,如何将宏应用于列表?

所以你必须要么求助于使用 eval:

(defmacro functionize [macro]
  `(fn [& args#] (eval (cons '~macro args#))))

(defmacro my-match [e ems]
  `(apply (functionize m/match) [~e] ~ems))

或者以不同的方式解决问题(执行运行时模式匹配而不是编译时模式匹配)。

于 2016-05-15T19:20:19.870 回答
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? Tupelo 库中的函数。 样品:

(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
于 2016-05-15T22:39:39.330 回答