Functions have always the same structure: an operator and n operands. The operator can be a function or an expression that returns a function.
(+ 1 2 3 4) ;; => 10
(* 1 2 3 4) ;; => 24
(first [1 2 3 4]) ;; => 1
(or + -) ;; => returns another function: + (PLUS) in this case
((or + -) 10 20) ;; => 30
((first [+ -]) 10 20) ;; => 30
Clojure can have higher functions: functions that receive another functions as arguments
(map inc [1 2 3]) ;; => (2 3 4) inc function if the first argument and it's applied for each element of the second argument, a vector
Function arguments are evaluated recursively
(+ (inc 199) (/ 100 (- 7 2)))
(+ 200 (/ 100 (- 7 2))) ; evaluated "(inc 199)"
(+ 200 (/ 100 5)) ; evaluated (- 7 2)
(+ 200 20) ; evaluated (/ 100 5)
220 ; final evaluation
;; example extracted from Daniel Higginbotham (Clojure for the Brave and True)
- defn
- function name
- a docstring (optional
- parameters listed in brackets
- function body
(defn my-function
"Any docstring explaining the function"
[name]
(str name " and anything else"))
You can view the docstring of a method by calling the function doc
(doc man) => print 'man' function documentation
Functions support arity overloading
(defn overloading-things
([param1 param2]
(do-a-funny-stuff-with param1 param2))
([param1]
(overloading-things param1 "a fixed string value")))
(defn i-drive
([whose vehicle]
(str "I drive " whose " " vehicle))
([vehicle]
(i-drive "my" vehicle))
([]
(i-drive "my car")))
(i-drive) ; => "I drive my car"
(i-drive "truck") ; => "I drive my truck"
(i-drive "her" "motorcycle") ; => "I drive her motorcycle"
Functions can accept a rest parameter at the end, meaning you can pass n values to it
(defn send-cheer-message-to
([nickname]
(str "Hey " nickname ", cheers!")))
(defn cheers-to-all-friends
([& all-friends]
(map send-cheer-message-to all-friends)))
(cheers-to-all-friends "Metallica" "Omar Rodríguez-López" "Depeche Mode")
(defn my-favourite-things
[name & things]
(str "Hi! I'm " name ". And my favourite things are "
(clojure.string/join ", " things)))
(my-favourite-things "Mun-ha" "guitar" "sand" "rituals")
It allows you to bind name to collection elements
(defn my-collection
[[first-thing second-thing]]
(into [] [first-thing second-thing]) )
(my-collection ["element one" "element two" "element three"]) ; => ["element one" "element two"]
(defn band-and-song
[{:keys [band song]}]
(str "Band: " band "; Song: " song))
(band-and-song {:band "El luecos" :song "Los Valles"}) ; => "Band: El luecos; Song: Los Valles"
It can accept rest parameters
(defn my-collection
[[first-thing & the-rest]]
(str "the first thing is " first-thing " and the rest are "
(clojure.string/join ", " the-rest)))
(my-collection ["element one" "element two" "element three"]) ; => "the first thing is element one and the rest are element two, element three"
(fn [params]
function-body)
(map (fn [old-civilization] (str "In the old times, there were the " old-civilization))
["celtics" "romans" "fenicians"])
You can associate an anonymous functions with a name
(def three_times (fn [num] (* num 3)))
(three_times 10) => 30
Another way to express the same in a shorter way
(def three_times #(* % 3)) ; here the percentage stands for the point where the param passed to the function will be used
(three_times 10) => 30
(#(str %1 " and " %2) "us" "them") ; => "us and them"
(#(str "some-attributes " %&) "yellow" "wisdom") ; => "some attributes (\"yellow\" \"wisdom\")"
(def my-printer (fn [names] (map #(str "My name is " %) names))
(my-printer ["Rodrigo" "Michele"]) ; => ("My name is Rodrigo" "My name is Michele")
(def another-print #(map (fn [name] (str "My nickname is " name)) %))
(another-print ["El Fuerte" "La Cosinera"]) ; => ("My nickname is El Fuerte" "My nickname is La Cosinera")
(def another-print-model (fn [names] (map (fn [name] (str "Again my name is " name)) names)))
(another-print-model ["Rodrigo" "Michele"]); => ("Again my name is Rodrigo" "Again my name is Michele")
(def my-broken-printer #(map #(str "My name is " %) %)) ; throws java.lang.IllegalStateException: Nested #()s are not allowed
Closures
(defn multiply-by
[number]
#(* % number))
(def multiply-by-10 (multiply-by 10))
(multiply-by-10 10) ; => 100