Skip to content

Instantly share code, notes, and snippets.

@cairesr
Last active August 9, 2016 21:36
Show Gist options
  • Save cairesr/279bbafab84cf9fdda033497b7612d1b to your computer and use it in GitHub Desktop.
Save cairesr/279bbafab84cf9fdda033497b7612d1b to your computer and use it in GitHub Desktop.
Clojure Functions Basics

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)

Function definition

  • 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")

destructuring

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"

Anonymous functions

(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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment