"Can't let qualified name" when using clojure.core.match

597 views Asked by At

I'm using clojure.core.match and seeing the following error:

Can't let qualified name

My code resembles:

(match [msg-type]
       [MsgType/TYPE_1] (do-type-1-thing)
       [MsgType/TYPE_2] (do-type-2-thing))

Where MsgType/TYPE_1 comes from a Java class:

public class MsgType {
    public static final String TYPE_1 = "1";
    public static final String TYPE_2 = "2";
}

What does this error mean, and how can I work around it?

2

There are 2 answers

0
Drew Noakes On

The problem seems related to macro name binding, though I don't understand it deeply as I'm quite new to macros.

Originally I hoped using case rather than match would prove a viable workaround:

(case msg-type
      MsgType/TYPE_1 (do-type-1-thing)
      MsgType/TYPE_2 (do-type-2-thing))

However the above doesn't work. case matches on the symbol MsgType/TYPE_n, not the evaluation of that symbol.

The best I've found so far is to convert the value coming in to a keyword and match that way:

(def type->keyword
     {MsgType/TYPE_1 :type-1
      MsgType/TYPE_2 :type-2})

(case (type->keyword msg-type)
      :type-1 (do-type-1-thing)
      :type-2 (do-type-2-thing))
0
Chuck On

In general, pattern matching is not the right tool for comparing one variable with another. Patterns are supposed to be either literals such as 1 or :a, destructuring expressions or variables to be bound. So, for example, take this expression:

(let [a 1
      b 2]
  (match [2]
    [a] "It matched A"
    [b] "It matched B"))

You might expect it to yield "It matched B" since the variable b is equal to 2, but in fact it will bind the value 2 to a new variable named a and yield "It matched A".

I think you're looking for condp =. It's basically what you wish case would be.

(condp = msg-type
  MsgType/TYPE_1 (do-type-1-thing)
  MsgType/TYPE_2 (do-type-2-thing))