defn

added
1.0

ns
clojure.core

type
macro

(defn name doc-string? attr-map? [params*] prepost-map? body) (defn name doc-string? attr-map? ([params*] prepost-map? body) + attr-map?)

Same as (def name (fn [params* ] exprs*)) or (def
name (fn ([params* ] exprs*)+)) with any doc-string or attrs added
to the var metadata. prepost-map defines a map with optional keys
:pre and :post that contain collections of pre or post conditions.

                user=> (defn foo [a b c]
\t    (* a b c))
#'user/foo
user=> (foo 1 2 3)
6

user=> (defn bar [a b & [c]]
         (if c
           (* a b c)
           (* a b 100)))
#'user/bar
user=> (bar 5 6)
3000
user=> (bar 5 6 2)
60

user=> (defn baz [a b & {:keys [c d] :or {c 10 d 20}}]
         (* a b c d))
#'user/baz
user=> (baz 2 3)
1200
user=> (baz 2 3 :c 5)
600
user=> (baz 2 3 :c 5 :d 6)
180

user=> (defn boo [a b & {:keys [c d] :or {c 10 d 20} :as all-specified}]
          (println all-specified)
          (* a b c d))
#'user/boo
user=> (boo 2 3)
nil
1200
user=> (boo 2 3 :c 5)
{:c 5}
600
user=> (boo 1 2 :d 3 :c 4)
{:c 4, :d 3}
24

            
                user=> (defn bar
         ([a b]   (bar a b 100))
         ([a b c] (* a b c)))
#'user/bar
user=> (bar 5 6)
3000
user=> (bar 5 6 2)
60

            
                ;; You can use destructuring to have keyword arguments. This would be a
;; pretty verbose version of map (in an example a bit more verbose than
;; the first above):

(defn keyworded-map [& {function :function sequence :sequence}]
  (map function sequence))

;; You can call it like this:

user=> (keyworded-map :sequence [1 2 3] :function #(+ % 2))
(3 4 5)


;; The declaration can be shortened with ":keys" if your local variables 
;; should be named in the same way as your keys in the map:

(defn keyworded-map [& {:keys [function sequence]}]
  (map function sequence))

            
                (defn somefn
  [req1 req2 ;required params
   & {:keys [a b c d e] ;optional params
      :or {a 1 ;optional params with preset default values other than the nil default
                  ; b takes nil if not specified on call
            c 3 ; c is 3 when not specified on call
            d 0 ; d is 0 --//--
                  ; e takes nil if not specified on call
           }
      :as mapOfParamsSpecifiedOnCall ;takes nil if no extra params(other than the required ones) are specified on call
      }]
  (println req1 req2 mapOfParamsSpecifiedOnCall a b c d e)
  )

=> (somefn 9 10 :b 2 :d 4)
;9 10 {:b 2, :d 4} 1 2 3 4 nil
nil
=> (somefn)
;ArityException Wrong number of args (0) passed to: funxions$somefn  ;clojure.lang.AFn.throwArity (AFn.java:437)
=> (somefn 9 10)
;9 10 nil 1 nil 3 0 nil
nil
=> (somefn 9 10 :x 123)
;9 10 {:x 123} 1 nil 3 0 nil
nil
=> (somefn 9 10 123)
;IllegalArgumentException No value supplied for key: 123  ;clojure.lang.PersistentHashMap.create (PersistentHashMap.java:77)
=> (somefn 9 10 123 45)
;9 10 {123 45} 1 nil 3 0 nil
nil
=> (try 
     (somefn 9 10 123)
     (catch IllegalArgumentException e (println "caught:" e)))
;caught: #<IllegalArgumentException java.lang.IllegalArgumentException: No value supplied for key: 123>
nil
            
                ;; :as only include parameters provided, not the default (:or) ones.
;; This is some boilerplate code to get around this. 
;; Hopefully not needed in the future revisions of Clojure.

(defn bar [f g h & {:keys [override]}]
  (let [default {:a 1 :b 2 :c 3}
        args (merge default override)]
    (conj '() f g h args)))

(bar 1 2 3 :override {:a 9 :z 5}) ; returns -> ({:z 5, :a 9, :b 2, :c 3} 3 2 1)