Introduction to FP
kapware
Paweł Kapała
in practice
Feedback loop
http://imgs.xkcd.com/comics/compiling.png
kapware
kapware
Read
Eval
Loop
Interactively with REPL!
All while the app is running!
kapware
Part 1: ABC
nil
kapware
false
true
kapware
0 1 2 3
0.2
2/3
2
5302542730
kapware
"str"
"Wawel"
"Kraków"
"hello world"
"John"
"Mścigniew"
kapware
:key
:title
:id
:chupacabra
:name
kapware
(list)
("a" "b" "c" "d" "e" "f")
(0 1 2 3 4 5 6 7)
(:a :b :c :d :e)
kapware
()
[vec]
[0 1 2 3 4 5 6]
["John" "Jane" "Lucy"]
[:title :name :id]
kapware
{map}
{:id 1 :name "John" :surname "Doe"}
{:subject "this" :predicate "is"
:preposition "a" :object "map"}
kapware
and they were all immutable!
kapware
immutablility leads to clean code
kapware
(def name binding)
a-symbol
bar
namespace/example
iamfoo
kapware
(foo arg1 arg2)
(str "a" "b" "c")
(conj [] 1 2 3 4)
(+ 2 4 6 7)
(first [1 2 3 4])
(assoc {:id 1 :name "John"} :surname "Doe")
(= {:id 1 :name "Joe"} {:id 1 :name "Joe"})
kapware
(defn fname [arg1 arg2]
body)
(defn greeter [arg1 arg2]
(str "Hello " arg1 " " arg2 "!"))
(defn plus [arg1 arg2]
(+ arg1 arg2))
kapware
#(body %1 %2)
#(+ %1 %2)
#(str "Hello " %1 " " %2 "!")
kapware
and they were pure*!
*at least for the most part
kapware
kapware
Part 2: The story
1 404 years ago...
kapware
There lived...
kapware
...Krakus
{:name "Krakus" :health 100}
(defn citizen [name]
{:name name :health 100})
(citizen "Krakus")
kapware
and he was king!
{:name "Krakus" :health 100 :title :king}
(defn promote [citizen title]
(assoc citizen :title title))
(defn king [name]
(promote (citizen name) :king))
(king "Krakus")
assoc returns new map with key value added to it
kapware
He had the greatest castle!
kapware
{:name "Wawel"}
(defn castle [name]
{:name name})
(castle "Wawel")
{:name "Wawel" :citizens [
{:name "Krakus" :health 100 :title :king}]}
(defn occupy [what whom]
(update what :citizens
(fnil conj []) whom))
(occupy (castle "Wawel") (king "Krakus"))
update returns map with a specified key changed by given function
conj returns collection with element appended
fnil executes specified function passing argument in case of nil
kapware
He was rich!
kapware
He had lots and lots of goods
{:energy 10 :size 10}
(defn food [energy]
{:energy energy :size 10})
(defn ram[] (food 10))
(defn cow[] (food 20))
(ram)
kapware
... stored at the castle
{:name "Wawel" :goods [{:energy 10 :size 10}]}
(defn store [structure food]
(update structure :goods
(fnil conj []) food))
(store (castle "Wawel") (ram))
kapware
... I said a lot!
({:energy 20 :size 10}
{:energy 20 :size 10}
{:energy 20 :size 10}
;... 15 more
{:energy 20 :size 10}
{:energy 20 :size 10})
(repeatedly 20 cow)
repeatadly returns (lazy) collection containing function result times the number specified, or infinite if size is not specified
kapware
He had bravest knights
kapware
(defn knight [name]
(assoc
(promote (citizen name) :knight)
:power 100))
(knight "Małowuj")
{:name "Małowuj" :title :knight :power 100}
kapware
... a lot of them!
{:name "Wawel" :citizens [
{:name "Małowuj" :title :knight :power 100 :health 100}
{:name "Minigniew" :title :knight :power 100 :health 100}
{:name "Gromisław" :title :knight :power 100 :health 100}
{:name "Nowosiodł" :title :knight :power 100 :health 100}
{:name "Twardomir" :title :knight :power 100 :health 100}
{:name "Włościobyt" :title :knight :power 100 :health 100}]}
(reduce occupy (castle "Wawel")
(map knight ["Małowuj" "Minigniew" "Gromisław"
"Nowosiodł" "Twardomir" "Włościobyt"]))
map executes function for each collection element and returns a collection of results
kapware
reduce calls two-arg function on a first element of the collection, then passes the return back to the function as a first argument and takes next element of the collection...
... but one day around 1:31pm
kapware
Dragon appeared!
(defn dragon [name]
{:name name :health 1000 :power 1000})
(dargon "Smok")
{:name "Smok" :health 1000 :power 1000}
... and it flew right onto Wawel!
(occupy (castle "Wawel") (dragon "Smok"))
kapware
{:name "Wawel" :citizens [{:name "Smok"
:health 1000 :power 1000}]
... and it was ever hungry!
(defn eat [who what]
(merge-with + who what))
(eat (dragon "Smok") (ram))
{:name "Smok" :health 1000 :power 1000
:energy 10 :size 10}
kapware
merge-with combines two map into one using provided function (+ in this case) on the values of matching keys
King ordered: "kill the beast!"
(defn attack [target who]
(update target :health
(fnil - 0) (:power who 0)))
(attack (dragon "Smok") (knight "Minigniew"))
{:name "Smok" :health 900 :power 1000}
kapware
kapware
but the dragon struck back!
; {:name "Minigniew" :health -900
; :title :knight :power 100}
true
(defn dead? [who]
(<= (:health who 0) 0))
(dead?
(attack (knight "Minigniew") (dragon "Smok")))
kapware
Skuba had an idea and took ram and some sulfur and tar
(defn sulfur []
{:thirst 500})
(defn tar []
{:size 500))
(defn ram-with-sulfur-and-tar []
(merge-with + (ram) (sulfur) (tar)))
(ram-with-sulfur-and-tar)
{:energy 10 :size 510 :thirst 500}
kapware
Trojan Ram!
... and the dragon ate it
(eat (dragon "Smok")
(ram-with-sulfur-and-tar))
{:name "Smok" :health 1000 :power 1000
:energy 10 :size 510 :thirst 500}
kapware
with a headache...
kapware
...and after drinking 100 galons
(defn water []
{:thirst -1 :size 10})
(defn vistula []
(repeatedly water))
(take 100 (vistula))
kapware
({:thirst -1 :size 10}
{:thirst -1 :size 10}
{:thirst -1 :size 10}
{:thirst -1 :size 10}
;... 96x more
)
the dragon blew out to pieces!
kapware
({:name "Smok-0" :health -1000 :power 1000}
{:name "Smok-1" :health -1000 :power 1000}
{:name "Smok-2" :health -1000 :power 1000}
{:name "Smok-3" :health -1000 :power 1000}
;... 96x more
)
(defn pieceof [who no]
(-> who
(update :name str "-" no)
(assoc :health -1000)))
(map #(pieceof (dragon "Smok") %1) (range 100))
-> Is called "a threading macro" that passes result of previous function call as first parameter to next call in block, the above is equivalent to:
(assoc (update who :name str "-" no) :health -1000)
He did it for Kraków !
kapware
The end
kapware
Simple? Perfect!
kapware
https://github.com/kapware/clj-krakus/
So you want to learn clojure?
kapware
4clojure.com
Clojure for the Brave and True
clojure.org
Structure and interpretation of computer programs
Mastering Clojure
clojurekoans.com
Find your mentor!
kapware
Thank you!
kapware
Introduction to functional programming in practice
By kapware
Introduction to functional programming in practice
- 733