You're viewing version 1.2.0 of case. The latest stable version of Clojure Core is 1.3.0.
1.2.0 Arrow_down_16x16
  • (case e & clauses)
Takes an expression, and a set of clauses.

Each clause can take the form of either:

test-constant result-expr

(test-constant1 ... test-constantN) result-expr

The test-constants are not evaluated. They must be compile-time
literals, and need not be quoted. If the expression is equal to a
test-constant, the corresponding result-expr is returned. A single
default expression can follow the clauses, and its value will be
returned if no clause matches. If no default expression is provided
and no clause matches, an IllegalArgumentException is thrown.

Unlike cond and condp, case does a constant-time dispatch, the
clauses are not considered sequentially. All manner of constant
expressions are acceptable in case, including numbers, strings,
symbols, keywords, and (Clojure) composites thereof. Note that since
lists are used to group multiple constants that map to the same
expression, a vector can be used to match a list if needed. The
test-constants need not be all of the same type.

1 Example top

  • user=> (let [mystr "hello"]
             (case mystr
               "" 0
               "hello" (count mystr)))
    5
    
    user=> (let [mystr "no match"]
             (case mystr
                   "" 0
                   "hello" (count mystr)))
    No matching clause: no match
      [Thrown class java.lang.IllegalArgumentException]
    
    user=> (let [mystr "no match"]
             (case mystr
                   "" 0
                   "hello" (count mystr)
                   "default"))
    "default"
    
    ;; You can give multiple values for the same condition by putting
    ;; those values in a list.
    user=> (case 'y
                 (x y z) "x, y, or z"
                 "default")
    "x, y, or z"
    
    user=> (let [myseq '(1 2)]
             (case myseq
                   (()) "empty seq"
                   ((1 2)) "my seq"
                   "default"))
    "my seq"
    
    ;; "The test-constants are not evaluated.They must be compile-time
    ;; literals, and need not be quoted." 
    user=> (let [myvec [1 2]]
             (case myvec
                   [] "empty vec"
                   (vec '(1 2)) "my vec"
                   "default"))
    "default"
    
Log in to add / edit an example.

See Also top

  • 0
    clojure.core/cond

    Takes a set of test/expr pairs. It evaluates each test one at a tim

  • 0
    clojure.core/condp

    Takes a binary predicate, an expression, and a set of clauses. Each

Log in to add a see also.

Plus_12x12 Minus_12x12 Source clojure/core.clj:5278 top

(defmacro case 
  "Takes an expression, and a set of clauses.

  Each clause can take the form of either:

  test-constant result-expr

  (test-constant1 ... test-constantN)  result-expr

  The test-constants are not evaluated. They must be compile-time
  literals, and need not be quoted.  If the expression is equal to a
  test-constant, the corresponding result-expr is returned. A single
  default expression can follow the clauses, and its value will be
  returned if no clause matches. If no default expression is provided
  and no clause matches, an IllegalArgumentException is thrown.

  Unlike cond and condp, case does a constant-time dispatch, the
  clauses are not considered sequentially.  All manner of constant
  expressions are acceptable in case, including numbers, strings,
  symbols, keywords, and (Clojure) composites thereof. Note that since
  lists are used to group multiple constants that map to the same
  expression, a vector can be used to match a list if needed. The
  test-constants need not be all of the same type."
  {:added "1.2"}

  [e & clauses]
  (let [ge (with-meta (gensym) {:tag Object})
        default (if (odd? (count clauses)) 
                  (last clauses)
                  `(throw (IllegalArgumentException. (str "No matching clause: " ~ge))))
        cases (partition 2 clauses)
        case-map (reduce (fn [m [test expr]]
                           (if (seq? test)
                             (into m (zipmap test (repeat expr)))
                             (assoc m test expr))) 
                           {} cases)
        [shift mask] (if (seq case-map) (min-hash (keys case-map)) [0 0])
        
        hmap (reduce (fn [m [test expr :as te]]
                       (assoc m (shift-mask shift mask (hash test)) te))
                     (sorted-map) case-map)]
    `(let [~ge ~e]
       ~(condp = (count clauses)
          0 default
          1 default
          `(case* ~ge ~shift ~mask ~(key (first hmap)) ~(key (last hmap)) ~default ~hmap 
                        ~(every? keyword? (keys case-map)))))))
Used in 3 other vars case do-report do-report

Comments top

2 comment(s) for case.

the third example describing myseq may be incorrect. I think we have to use vectors for comparing list of compile time constants.

(let [myseq [1 2]]
 (case myseq
  [] "empty seq"
  [1 2] "my seq"
  "default"))

The parenthesized test conditions are used when multiple test conditions give the same output (output expression). In my case , since both [true, true] and [false, false] return true, i have put them within parenthesis.

(defn equ
 [a b]
 (case [a b]
   ([true true] [false false]) true
   true))

(equ true true) ;; returns true
(equ false false) ;; returns true
(equ false true) ;; return false
(equ true false) ;; returns false

I updated that example with myseq to reflect behavior of Clojure 1.2.0 on my machine. I also added an additional example to explicitly demonstrate multiple values for the same condition.

Log in to add a comment.