Created
April 14, 2015 11:31
-
-
Save dreoliv/c6b5181da10710b4639c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(+ 1 2) | |
; KEYWORDS | |
; used to map values in hashes | |
(def person {:name "Andre" | |
:city "Florianopolis"}) | |
; Keywords are functions that look themselves up in collections passed to them. | |
(:city person) | |
; Double-colon before a keyword creates it in the global namespace. | |
(def pizza {:name "Baggio" | |
:location "Florianopolis" | |
::location "-43 +12"}) | |
pizza | |
(:user/location pizza) | |
(:location pizza) | |
; | |
; Keywords are named values. Means they have a name: | |
(name :user/location) | |
(namespace :user/location) | |
(namespace :location) | |
; SYMBOLS | |
; Are identifiers that evaluate to values (held by vars). | |
(defn average [numbers] | |
(/ (apply + numbers) (count numbers))) | |
(average [10, 20, 30]) | |
; ^ average is a symbol. refers to the function held in var named average. | |
; Commas are optional | |
(= [1, 2, 3] [1 2 3]) | |
; def defines variables in the current namespace. | |
(def x 1) | |
x | |
; *ns* shows the current namespace | |
*ns* | |
; ns function changes the current namespace | |
(ns user) | |
; CLOJURE SPECIAL FORMS | |
; 1. quote: suppresses evaluation of expressions. Symbols evaluate to themselves. | |
x | |
(quote x) | |
(symbol? (quote x)) | |
; ' (aposthrofe) is the same as quote. | |
x | |
'x | |
; anything can be quoted. | |
; quoting lists supress evaluation, returning the list itself. | |
(+ x x) | |
'(+ x x) | |
(list? '(+ x x)) | |
(list '+ 'x 'x) | |
; 2. do: evaluates a list of expressions. Last expression is the return value. | |
(do | |
(println "hi") | |
(apply * [4 5 6])) | |
; 3. def: define vars. | |
(def p "foo") | |
p | |
; 4. let: create local bindings. | |
(defn hypot | |
[x y] | |
(let [x2 (* x x) | |
y2 (* y y)] | |
(Math/sqrt (+ x2 y2)))) | |
(hypot 3.0 4.0) | |
; all local bindings created by let are immutable | |
; 5. destructuring: pulls apart collections | |
; - sequential destructuring: works with sequential collections. | |
(def v [42 "foo" 99.2 [5 12]]) | |
v | |
(let [[a b c] v] | |
(+ a c)) | |
; destructuring can be nested. | |
(let [[a _ _ [b c]] v] | |
(+ a b c)) | |
; & gets the rest. | |
(let [[a & rest] v] | |
rest) | |
; :as makes the next symbol hold the original values | |
(let [[x _ y :as original] v] | |
(conj original (+ x y))) | |
; - map destructuring: works with maps. | |
(def m {:a 5 :b 6 | |
:c [7 8 9] | |
:d {:e 10 :f 11} | |
"foo" 88 | |
42 false}) | |
(let [{a :a b :b} m] | |
(+ a b)) | |
(let [{f "foo" | |
v 42} m] | |
(+ f (if v 0 1))) | |
; map destructuring syntax can be used with vectors if indexes are provided. | |
(let [{a 1 b 4} [1 2 3 4 5]] | |
(+ a b)) | |
; can be nested. | |
(let [{{a :e} :d} m] | |
(* 2 a)) | |
; can be mixed with sequential destructuring | |
(let [{[x _ y] :c} m] | |
(+ x y)) | |
; default values | |
(def m2 {:a 1 :b 2}) | |
(let [{a :a b :x | |
:or {b 10}} m] | |
(+ a b)) | |
; DRY, or mapping keys to locals with same name | |
(def chas {:name "Chas" | |
:age 31 | |
:location "Massachusetts"}) | |
(let [{:keys [name age location]} chas] | |
(format "%s is %s years old and lives in %s" name age location)) | |
; Destructuring a vector of key-value pairs into a map: (using the rest - & - notation). | |
(def user-info [:username "andre" :name "Andre" :city "floripa"]) | |
(let [[& {:keys [username name city]}] user-info] | |
(format "%s (%s) is from %s" username name city)) | |
; 6. FN: create functions | |
(fn [x] (+ 10 x)) | |
; calling functions with parentheses: | |
((fn [x] (+ 10 x)) 8) | |
; put a function in a var: | |
(def add-10 (fn [x] (+ 10 x))) | |
(add-10 8) | |
; defn is short for this (create and put it in a var) | |
(defn add-10 [x] | |
(+ 10 x)) | |
(add-10 9) | |
; multi-arity functions: | |
(defn add-default | |
([x] (+ x 1)) | |
([x y] (+ x y))) | |
(add-default 1) | |
(add-default 1 2) | |
; variadic functions: using destructuring in arguments | |
(defn concat-rest | |
[x & rest] | |
(apply str rest)) | |
(concat-rest 1 2 3 4) | |
; zero-arity functions | |
(defn adder | |
[& attrs] | |
(apply + (or attrs [0]))) | |
(adder) | |
(adder 1 2 3 5 7 9 11) | |
; keyword arguments, also using destructuring. | |
(defn now [] (java.util.Date.)) | |
(defn make-user | |
[username & {:keys [email join-date] | |
:or {join-date (now)}}] | |
{:username username | |
:join-date join-date | |
:email email}) | |
(make-user "andre" | |
:email "[email protected]") | |
; literals for anonymous functions | |
(#(+ %1 %2) 2 1) | |
(read-string "#(+ %1 %2)") | |
; 7. IF conditional | |
(if true "andre" "bernardes") | |
; 8. Loop and Recur | |
(loop [x 5] ; implicit let form | |
(if (neg? x) | |
x ; final expression, returns its value | |
(recur (dec x)))) ; or back to the loop, rebinds x to (dec x) | |
; functions are a loop head: | |
(defn countdown | |
[x] | |
(if (zero? x) | |
:blastoff! | |
(do (println x) | |
(recur (dec x))))) | |
; ****************************************************************** | |
; Functional programming in Clojure: | |
; - Preference for working with immutable values | |
; - Immutable data structures | |
; - Functions as values > higher order functions | |
; - Declarative processing of data | |
; - Incremental composition for higher level abstractions | |
; FIRST CLASS AND HIGHER ORDER FUNCTIONS | |
(defn call-twice [f x] | |
(f x) | |
(f x)) | |
; Higher order functions: functions that receive other functions as | |
; arguments or return a function as a result. Examples: | |
; map | |
(map clojure.string/lower-case ["Andre" "Bernardes" "Oliveira"]) | |
(map + [1 2 3] [4 5 6]) | |
; reduce : reduce a collection to a single value | |
(reduce max [0 10 8 2]) | |
(reduce + 1 [2 3 4]) | |
(reduce | |
(fn [collection value] | |
(assoc collection value (* value value))) | |
{} | |
[1 2 3 4]) | |
; Partial Apply | |
; apply: send an array as arguments to a function | |
(apply hash-map [:a 5 :b 6]) | |
(apply + 1 2 [3 4 5]) | |
; partial apply: define a function with preset arguments | |
(def only-strings (partial filter string?)) | |
(only-strings [1 "a" 2 "b"]) | |
; Function Composition | |
; comp: compose functions. | |
(defn negated-sum-str ; regular function | |
[& numbers] | |
(str (- (apply + numbers)))) | |
(negated-sum-str 10 100 5 12) | |
(def negated-mult-str (comp str - *)) ;pipeline with comp | |
(negated-mult-str 1 2 5) | |
(defn split-camel [s] | |
(str/split s #"(?<=[a-z])(?=[A-Z])")) | |
(def camel->keyword | |
(comp keyword | |
str/join | |
(partial interpose \-) | |
(partial map str/lower-case) | |
#(str/split % #"(?<=[a-z])(?=[A-Z])"))) | |
(camel->keyword "FooBar") | |
(camel->keyword "fooBar") | |
(def camel-pairs->map | |
(comp (partial apply hash-map) | |
(partial map-indexed (fn [i x] | |
(if (odd? i) | |
x | |
(camel->keyword x)))))) | |
(camel-pairs->map ["FooBar" 3 "lowFooBar" 5]) | |
; Writing Higher-order functions | |
; a function that returns a function | |
(defn adder | |
[n] | |
(fn [x] (+ n x))) | |
((adder 5) 18) | |
(defn doubler | |
[f] | |
(fn [& args] | |
(* 2 (apply f args)))) | |
((doubler +) 1 2 3) | |
; example: logging system | |
; print-logger produces a function that logs messages to a writer | |
(defn print-logger | |
[writer] | |
#(binding [*out* writer] | |
(println %))) | |
; file-logger produces a function that uses print-logger to | |
; print to a file. | |
(require 'clojure.java.io) | |
(defn file-logger | |
[file] | |
#(with-open [f (clojure.java.io/writer file :append true)] | |
((print-logger f) %))) | |
; multi-logger returns a function that writes to multiple loggers | |
; at once | |
(defn multi-logger | |
[& logger-fns] | |
#(doseq [f logger-fns] | |
(f %))) | |
(def log (multi-logger | |
(print-logger *out*) | |
(file-logger "messages.log"))) | |
; adds timestamps to the logger | |
(defn timestamped-logger | |
[logger] | |
#(logger (format "[%1$tY-%1$tm-%1$te %1$tH:%1$tM:%1$tS] %2$s" (java.util.Date.) %))) | |
(def log-timestamped | |
(timestamped-logger | |
(multi-logger | |
(print-logger *out*) | |
(file-logger "messages.log")))) | |
; PURE FUNCTIONS | |
; memoization | |
(defn prime? | |
[n] | |
(cond | |
(== 1 n) false | |
(== 2 n) true | |
(even? n) false | |
:else (->> (range 3 (inc (Math/sqrt n)) 2) | |
(filter #(zero? (rem n %))) | |
empty?))) | |
(time (prime? 1125899906842679)) | |
(let [m-prime? (memoize prime?)] ; memoized function | |
(time (m-prime? 1125899906842679)) | |
(time (m-prime? 1125899906842679))) ; second time returns cached result | |
; * Important: always use memoize in local scopes | |
; CHAPTER 3 - COLLECTIONS AND DATA STRUCTURES | |
; 1. Used in terms of abstractions | |
; 2. Immutable and Persistent | |
; COLLECTIONS | |
(conj [1 2] 3) | |
(seq #{1 2 3}) | |
(count {:a 1 :b 2}) | |
(empty '(1 2 3)) | |
(= [1 2] [1 2]) | |
; SEQUENCES | |
(seq "Clojure") | |
(seq {:a 5 :b 6}) | |
(first "Clojure") | |
(rest "clojure") | |
(next "clojure") | |
(rest [1]) ; Returns empty | |
(next [1]) ; Returns nil | |
; seqs are only "realised" when needed | |
(let [s (range 1e6)] | |
(time (count s))) ; takes a long time bc has to realise the seq before counting | |
(let [s (apply list (range 1e6))] | |
(time (count s))) ; lists are realized and track their size | |
; Creating Seqs | |
; cons - prepend value to collection, returns a seq | |
(cons 0 (range 1 5)) | |
; list* - sequential cons. | |
; don't do this: | |
(cons 1 (cons 2 (range 3 5))) | |
; do this instead: | |
(list* 1 2 (range 3 5)) | |
; Lazy Evaluation | |
(defn random-ints | |
"Returns a lazy seq of random integers in the range [0, limit)." | |
[limit] | |
(lazy-seq | |
(cons (rand-int limit) | |
(random-ints limit)))) | |
(take 10 (random-ints 50)) | |
; Fibonnaci sequence using a lazy seq | |
; I actually made this myself! | |
(defn fib | |
([] | |
(lazy-seq | |
(list* 0 1 1 (fib 1 1)))) | |
([x1 x2] | |
(let [sum (+ x1 x2)] | |
(lazy-seq | |
(cons sum (fib x2 sum)))))) | |
(take 10 (fib)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment