“ the greatest single programming language ever designed ”
- Alan Kay, on Lisp
“ Lisp is worth learning for the profound enlightenment experience you will have when you finally get it; that experience will make you a better programmer for the rest of your days, even if you never actually use Lisp itself a lot. ”
- Eric Raymond, “How to Become a Hacker”
;; this is a comment
;; creates a global var
(def x 1)
(def hello-1 (fn []
"Hello World!"))
(def hello-2 #(str "Hello " %))
;; creates a global var with a function as value
(defn hello-3
"Returns hello world"
[]
"Hello World!")
(defn hello-4
"Multi arity function."
([] "Hello world!")
([name] (str "Hello " name "!")))
;; data structures
(def a-vector [1 2 3])
(def another-vector (vector 1 2 3))
(conj a-vector 4)
(def a-list '(1 2 3))
(def another-list (list 1 2 3))
(conj a-list 4)
(def a-set #{1 2 3})
(def another-set (set (list 1 2 3 1)))
(conj a-set 4)
(def a-map {:foo "bar" :a 1})
(def another-map (hash-map :foo 1 :bar 2))
(assoc a-map :b 2)
;; (first a-vector)
;; (rest a-vector)
;; (drop 2 a-vector)
;; (pop a-vector)
;; (peek a-vector)
;; (into {:c "value"} a-map)
;; (into [5 6 7] a-vector)
;; (concat [1 2] [3 4])
(def users [{:name "James" :age 26} {:name "John" :age 43}])
;; update the age of the second (index 1) user
(assoc-in users [1 :age] 44)
// 2 dates in a domain class
Calendar scheduledArrivalTime;
Calender expectedArrivalTime;
Calendar cal = getArrivalTimeFromRemote() // Calender.getInstance()
// set arrivalTimes
scheduledArrivalTime = cal
expectedArrivalTime = cal;
// many, many lines of code later......
// somewhere in the code: 2 minutes delay for expectedArrivalTime
expectedArrivalTime.add(Calendar.MINUTE, 2);
// happy debugging :)
(defn add-1
"Sum up given parameters."
[& more]
(apply + more))
(defn destruct-1
"Extract firstname and lastname and returns fullname."
[{:keys [:firstname :lastname]}]
{:fullname (str firstname " " lastname)})
(defn destruct-2
"Extract firstname and lastname but also add defaults if one of the
names do not exist. Returns concatenated fullname string."
[{:keys [:firstname :lastname]
:or {:firstname "John" :lastname "Doe"}}]
{:fullname (str firstname " " lastname)})
;; if and cond
(defn my-even?
"Returns true if number is even."
[n]
(if (even? n)
true
false))
(defn greeting
"Returns the greeting in the given language. Defaults to :english"
([] "Hello with with default argument")
([language]
(cond (= language :french) "Bonjour"
(= language :spanish) "Hola"
:else "Hello")))
;; let
(defn area-circle
"Returns the area of a circle with the given radius"
[radius]
(let [pi 3.1415
radius-squared (* radius radius)]
(* pi radius-squared)))
;; loops
(defn factorial
"Returns the factorial of the given number."
[n]
(loop [i n
acc 1]
(if (zero? i)
acc
(recur (dec i) (* acc i)))))
(defn print-list
"Prints all entries of given list"
[collection]
(doseq [entry collection]
(println entry)))
;; lazy data structures
(def natural-numbers (iterate inc 1))
;; (take 5 natural-numbers)
;; (inc (inc (inc 1)))
;; (-> 1 inc inc inc)
;; map filter reduce
(def even-numbers (filter even? natural-numbers))
(defn sum-of-squares
"Returns the sum of the given numbers squared."
[& numbers]
(reduce + 0 (map (fn [x]
(* x x))
numbers)))
;; partial
(def even-numbers-2 (iterate (partial + 2) 0))
;; (take 10 even-numbers-2)
(def fifth (comp first rest rest rest rest))
(defn fnth
"Returns a function which returns n-th item from given sequence."
[n]
(apply comp (cons first (take (dec n) (repeat rest)))))
;; ((fnth 5) [1 2 3 4 5 6])
(defn fib [n]
(condp = n
0 1
1 1
(+ (fib (dec n)) (fib (- n 2)))))
(def memo-fib
(memoize (fn [n]
(condp = n
0 1
1 1
(+ (memo-fib (dec n)) (memo-fib (- n 2)))))))
;; concurrency refs (in-memory transactions)
(def account-a (ref 1000))
(def account-b (ref 0))
(defn transfer-money
"Transfers the given amount of money from account a to account b"
[amount a b]
(dosync
(alter a #(- % amount))
(alter b #(+ % amount))))
;; @account-a
;; @account-b
;; (transfer-money 100 account-a account-b)
;; pre- and post conditions
;; design-by-contract
(defn constrained-sqr [x]
{:pre [(pos? x)]
:post [(> % 16), (< % 225)]}
(* x x))
“ If you give someone Fortran, he has Fortran. If you give someone Lisp, he has any language he pleases. ”
- Guy Steele (Programming Language guru, contributed to Java Language Spec, Scheme, ECMAScript, Common Lisp, C, co-auther of emacs)
“ First rule of macros: don't write macros. ”
- anonymous
// java 1.4 and before
for (int i = 0; i < list.size(); i++) {
String s = (String) list.get(i);
// do something with list item...
}
// java 1.5 (8 year later)
for (String s : list) {
// do something with list item
}
;; for-each macro
(defmacro for-each
"Simulates the java for-each loop"
[[sym coll] & body]
`(loop [coll# ~coll]
(when-let [[~sym & xs#] (seq coll#)]
~@body
(recur xs#))))
;; (for-each [x [1 2 3]]
;; (println x))
;; infix macro
(defmacro infix
"Use this macro to get a familiar syntax."
[infixed]
(list (second infixed) (first infixed) (last infixed)))
;; (infix (1 + 2))
;; (macroexpand-1 '(infix (1 + 2)))
(defmacro unless-1
"Inverted if"
[test & branches]
(conj branches (list 'not test) 'if))
;; (unless-1 (= 1 1)
;; true
;; false)
(defmacro unless-2
"Inverted if, easier"
[test & branches]
`(if (not ~test)
~@branches))
(defmacro my-and
""
([] true)
([x] x)
([x & next]
`(let [and# ~x]
(if and# (my-and ~@next) and#))))
;; (my-and true false)
;; (pprint (macroexpand-1 '(my-and true false)))
- Joy of Clojure - Michael Fogus and Chris Houser