Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure core.match can't match on class

When evaling this super simple core.match expression I get:

(match [(class "3.14")]
       [Integer] "Integer"
       [Double] "Doubler")
; => "Integer"

How can this be correct, am I missing something fundamental about core.match? Doing a macroexpand-1 on this form gives me:

=> (clojure.core/let [ocr-2751 (class "3.14")] (clojure.core/let [Integer ocr-2751] "Integer"))

Any pointers appreciated.

like image 458
klozovin Avatar asked Dec 07 '22 00:12

klozovin


2 Answers

Like @Arthur said, normally core.match will bind values to symbols. However, apparently, it first tries to match against locals. Who knew?

Anyway, bind the classes as locals in a let before matching and you're good to go:

(let [Integer java.lang.Integer
      String  java.lang.String]
  (match [(class "3.14")]
         [Integer] "Integer"
         [String] "String"))
like image 191
Beyamor Avatar answered Dec 29 '22 01:12

Beyamor


core.match allows you to give a name to one of the values in a match clause like so (from the examples)

(let [x 1 y 2]
  (match [x y]
    [1 b] b
    [a 2] a
    :else nil))

In this example if the first matching value is a one, then in the expression used to generate the result, the second value will be accessible under the name b.

Because any symbol in a match clause is interpreted as an instruction to bind the corresponding value to that name, in your case the name Integer is being bound to the value java.lang.String

user> (match [(class "3.14")]
             [Integer] Integer
             [Double] "Doubler")
java.lang.String

user> (match [(class "3.14")]
             [name-to-bind] name-to-bind
             [Double] "Doubler")
java.lang.String

It's not clear from the documentation that there is a way to use core.match to evaluate the match clause instead of binding to it. It is possible to workaround this by matching against a string, though it looses some of the elegance :

user> (match [(str (class (int 3)))]
             ["class java.lang.Integer"] "Integer"
             ["class java.lang.String"] "String"
             ["class java.lang.Double"] "Double")
"Integer"
user> (match [(str (class "3.14"))]
             ["class java.lang.Integer"] "Integer"
             ["class java.lang.String"] "String"
             ["class java.lang.Double"] "Double")
"String"
user> (match [(str (class 3.14))]
             ["class java.lang.Integer"] "Integer"
             ["class java.lang.String"] "String"
             ["class java.lang.Double"] "Double")
"Double"
like image 28
Arthur Ulfeldt Avatar answered Dec 29 '22 00:12

Arthur Ulfeldt