|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
;;; FUNCTIONAL COMPOSITION DEMO ;;; |
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
|
|
;; define a vector [] of maps {key value} at the symbol 'the-watch' |
|
(def the-watch |
|
[{:name "Samuel Vimes" :species "Human" :rank "Commander"} |
|
{:name "Carrot Ironfoundersson" :species "Human, Dwarf (honorary)" :rank "Captain"} |
|
{:name "Fred Colon" :species "Human" :rank "Sergeant"} |
|
{:name "C. W. St J. (Nobby) Nobbs" :species "Human (licensed)" :rank "Lance-Corporal"} |
|
{:name "Angua von Überwald" :species "Werewolf" :rank "Lance-Corporal"} |
|
{:name "Detritus" :species "Troll" :rank "Lance-Corporal"}]) |
|
|
|
;; all expressions return a value. this one, a call to the 'count' |
|
;; function, returns the count of the elemnts in 'the-watch'. |
|
(count the-watch) |
|
|
|
;; |
|
|
|
;; defines a function at the symbol 'has-species? with two arguments. |
|
(defn has-species? |
|
[species character] |
|
;; re-find matches regular expressions to strings. |
|
(re-find species |
|
;; keywords are also functions when given a map! |
|
;; will return the value at ':species' key. |
|
(:species character))) |
|
|
|
;; partial composes a function with an argument 'baked' in. |
|
;; gives us a new function to use directly. |
|
;; regular expressions are written as strings with a # prefix. |
|
(def human? (partial has-species? #"Human")) |
|
|
|
;; filter composes a predicate - a true/false function - with a |
|
;; collection. returns only those which match the predicate. |
|
(filter human? the-watch) |
|
|
|
;; |
|
|
|
;; compose a string representation of a character |
|
(defn stringify |
|
[character] |
|
(str (:rank character) " " |
|
(:name character) ", " |
|
(:species character))) |
|
|
|
;; run each character through the stringify function |
|
(map stringify the-watch) |
|
|
|
;; |
|
|
|
(comment |
|
|
|
;; putting it all together to do something meaninful: |
|
;; println - our first 'impure' function! |
|
(println (clojure.string/join "\n" |
|
(concat (list "The Watch:" |
|
"-----------------------") |
|
(map stringify the-watch)))) |
|
|
|
;; |
|
|
|
;; make it readable by using '->>', a 'threading' macro, which |
|
;; reorganises code during compilation. |
|
;; semantically identical to the previous version. |
|
(->> the-watch |
|
(map stringify) |
|
(concat (list "The Ankh-Morpork Watch:" |
|
"-----------------------")) |
|
(clojure.string/join "\n") |
|
(println)) |
|
|
|
;; |
|
|
|
;; filter non-humans! |
|
(->> the-watch |
|
;; complement makes a function that returns the opposite boolean |
|
;; value to the function it is passed |
|
(filter (complement human?)) |
|
(map stringify) |
|
(concat (list "The Ankh-Morpork Watch:" |
|
"-----------------------")) |
|
(clojure.string/join "\n") |
|
(println)) |
|
|
|
;; |
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
;;; IMMUTABLE DATA DEMO ;;; |
|
;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
|
|
(def a "this is a") |
|
|
|
(println a) |
|
|
|
;; |
|
|
|
;; bind [1 2 3] to 'a' for the duration of this let form's contents |
|
(let [a [1 2 3]] |
|
(println a) |
|
|
|
;; rebind a |
|
(let [a [4 5 6]] |
|
(println a)) |
|
|
|
(println a)) |
|
|
|
;; |
|
|
|
(println a) |
|
|
|
;; |
|
|
|
;; an example that actually does something: |
|
|
|
(let [content (slurp "/Users/robert/quote.edn")] |
|
(println content) |
|
(let [content (read-string content)] |
|
(println (str "\n\t'" (:quote content) "' - " (:author content) "\n"))) |
|
(println content)) |
|
|
|
;; |
|
|
|
(println content) |
|
|
|
;; |
|
|