mac
mac

Reputation: 10085

Macro to pass patterns and results to core.match/match as a vector

I am struggling on how to construct a macro that lets me pass patterns and results to core.match/match in the form of a vector. I would like to be able to do this:

(let [x {:a 1}
      patterns [[{:a 2}] :high
                [{:a 1}] :low]]
     (my-match x patterns))

> :low

I have tried the below and several other approaches which do not work, unless I pass patterns as a literal.

(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

Upvotes: 3

Views: 128

Answers (2)

Alan Thompson
Alan Thompson

Reputation: 29966

The simplest way to solve your problem is with a plain old map:

(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

Since you have no "wildcard values", you don't need core.match at all. If you would like to match on wild-card values, please see the function wild-match? in the Tupelo library. Samples:

(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

Upvotes: 1

Timothy Pratley
Timothy Pratley

Reputation: 10662

Macros are expanded at compile time, so you cannot rely on runtime information (the value of a parameter) during expansion. The root problem is that you can't apply a macro in the same way you can apply a function.

In clojure, how to apply a macro to a list?

So you have to either resort to using eval:

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

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

Or approach the problem in a different way (do runtime pattern matching instead of compile time pattern matching).

Upvotes: 2

Related Questions