store/[org.clojure/clojure "1.8.0"] clj::clojure.core/condp

Community Documentation

Edit

Arities

[pred expr & clauses]

Docstring

Takes a binary predicate, an expression, and a set of clauses. Each clause can take the form of either:

test-expr result-expr
test-expr :>> result-fn

For each clause, (pred test-expr expr) is evaluated. If it returns logical true, the clause is said to be a match. If a binary clause matches, the result-expr is returned, if a ternary clause matches, its result-fn, which must be a unary function, is called with the result of the predicate as its argument, the result of that call being the return value of condp. 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.

Source

(defmacro condp
  "Takes a binary predicate, an expression, and a set of clauses.
  Each clause can take the form of either:

  test-expr result-expr

  test-expr :>> result-fn

  Note :>> is an ordinary keyword.

  For each clause, (pred test-expr expr) is evaluated. If it returns
  logical true, the clause is a match. If a binary clause matches, the
  result-expr is returned, if a ternary clause matches, its result-fn,
  which must be a unary function, is called with the result of the
  predicate as its argument, the result of that call being the return
  value of condp. 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."
  {:added "1.0"}

  [pred expr & clauses]
  (let [gpred (gensym "pred__")
        gexpr (gensym "expr__")
        emit (fn emit [pred expr args]
               (let [[[a b c :as clause] more]
                       (split-at (if (= :>> (second args)) 3 2) args)
                       n (count clause)]
                 (cond
                  (= 0 n) `(throw (IllegalArgumentException. (str "No matching clause: " ~expr)))
                  (= 1 n) a
                  (= 2 n) `(if (~pred ~a ~expr)
                             ~b
                             ~(emit pred expr more))
                  :else `(if-let [p# (~pred ~a ~expr)]
                           (~c p#)
                           ~(emit pred expr more)))))]
    `(let [~gpred ~pred
           ~gexpr ~expr]
       ~(emit gpred gexpr clauses))))

Example 1

Edit
;;this is with liberator
;;branching on request method
(defresource my-resource
  :exists? (fn [{:keys [db] {query-params :query-params 
                             body :body 
                             method :request-method} 
                 :request}]

             (condp = method
               :get (my-get-exists-fn)
               :post (my-post-exists-fn))))

Example 2

Edit
(condp (comp seq re-seq) "foo=bar"
  #"[+](\w+)"    :>> #(vector (-> % first (nth 1) keyword) true)
  #"[-](\w+)"    :>> #(vector (-> % first (nth 1) keyword) false)
  #"(\w+)=(\S+)" :>> #(let [x (first %)]
                        [(keyword (nth x 1)) (nth x 2)]))
;; => [:foo "bar"]

Example 3

Edit
;; See examples for "if" explaining Clojure's idea of logical true
;; and logical false.

Example 4

Edit
(condp some [1 2 3 4]
  #{0 6 7} :>> inc
  #{4 5 9} :>> dec
  #{1 2 3} :>> #(+ % 3))
;; => 3

Example 5

Edit
(condp #(%1 2 %2) 3
  = "eq"
  < "lt"
  > "gt")
"lt"

Example 6

Edit
;; Taken from the excellent clojure tutorial:
;; http://java.ociweb.com/mark/clojure/article.html

(do (print "Enter a number: ")
    ;; Java's stdout is line buffered
    ;; So we have to force flush it
    (flush)

    (let [reader (java.io.BufferedReader. *in*) ; stdin
          line   (.readLine reader)
          value  (try
                   (Integer/parseInt line)
                   (catch NumberFormatException e line))] ;use string val if not int
      (println
       (condp = value
         1 "one"
         2 "two"
         3 "three"
         (str "unexpected value, \"" value \")))
      (println
       (condp instance? value
         Number (* value 2)
         String (* (count value) 2))))
    nil)
;; > Enter a number:
;; < 3
;; > "three"
;; > 6
;; => nil

Example 7

Edit
(condp some [1 2 3 4]
  #{0 6 7} :>> inc
  #{5 9}   :>> dec)
;; => java.lang.IllegalArgumentException: No matching clause: [1 2 3 4]

Example 8

Edit
;; a recursive function to calculate length
;; same as 'count'
(defn length [lst]
  (condp = lst
    (list) 0 ; if empty list result 0
    (+ 1 (length (rest lst))))) ; default expression
;; => #'user/length

(length '(1 2 3))
;; => 3

Uses on crossclj