(if (pos? 1)
"one is positive"
"or is it?")
;=> "one is positive"
Control your own destiny or someone else will.
(if (pos? 1)
"one is positive"
"or is it?")
;=> "one is positive"
Chooses between two options
Returns a result
Only one branch is evaluated
A function call evaluates all arguments
Booleans: true
and false
nil
means nothing and is considered false in logical tests
Anything else is truthy
(if 5
"it's five!"
"no problem")
;=> "it's five!"
(if (pos? 1)
(do (prn "hi")
"one is positive")
"or is it?")
;;; "hi"
;=> "one is positive"
(when (pos? 1)
(prn "multiple expressions allowed")
:ok)
;;; multiple expressions allowed
;=> :ok
When test fails, nothing is evaluated
When test passes, the entire body is evaluated
Returns the last expression as a result
(def x {:cake 1})
(cond (= x 1) "one"
(= x :cake) "the cake is a lie"
(map? x) "it's a map!"
:else "not sure what it is")
;=> "it's a map!"
Multiple branches
:else
is not special, keywords are truthy
See also condp
and case
Built in primitives, not functions
def
, let
, quote
and fn
are special forms
Arguments are not evaluated
(if (= 1 2)
(prn "a")
(prn "b"))
;;; "b"
;=> nil
(defn if-fn [condition a b]
(if condition a b))
(if-fn (= 1 2)
(prn "a")
(prn "b"))
;;; a
;;; b
;=> nil
or
is a macro
(or true (println "Hello"))
;=> true
Arguments are not evaluated
Macros are used to implement and extend Clojure syntax
(or true false)
Expands to:
(let [a true] (if a a (let [b false] (if b b)))))
(apply or [true false true])
;;; CompilerException: Can't take value of a macro
(apply if [true :a :b])
;;; CompilerException: Unable to resolve symbol: if
Macros cannot be passed as arguments to functions |
Remember the special forms:
if
, do
, let
, quote
, var
, fn
, loop
, recur
, throw
, try
Control flow forms: cond
, or
, and
, when
Navigate to source: def
, defn
, defmacro
See :macro
in Metadata
Documentation
Writing macros is covered later in the course |
(defn sum-up [coll result] (if (empty? coll) result (sum-up (rest coll) (+ result (first coll)))))
Functions that invoke themselves are recursive
Recursion without consuming the stack
(defn sum-up-with-recur [coll result] (if (empty? coll) result (recur (rest coll) (+ result (first coll)))))
Recur can only occur where a function returns
Current frame will return the result of the next call
No further calculations needed
Current frame can be released
(loop [a 0 b 1] (if (< b 1000) (recur b (+ a b)) a))
Loop establishes bindings
Allows recur to the start of the loop
Special forms try
catch
finally
and throw
(try (inc "cat") (catch Exception e (println "cat cannot be incremented")) (finally (println "always"))
See manual end of section 5
(def grade [score] (cond (>= score 90) "A" (>= score 80) "B" (>= score 70) "C" (>= score 60) "D" :else "F"))
(deftest grade-test (is (= "B" (grade 85))))
(defn factorial [n] (loop [acc 1 x n] (if (<= x 1) acc (recur (* acc x) (dec x)))))
(deftest factorial-test (is (= 120 (factorial 5))))
(defn factorial2 ([n] (factorial2 1 n)) ([acc n] (if (<= n 1) acc (recur (* acc n) (dec n)))))
(deftest factorial2-test (is (= 120 (factorial2 5))))
(defn fib [limit] (loop [a 1 b 1] (if (>= b limit) a (recur b (+ a b)))))
(deftest fib-test (is (= 89 (fib 100))))