;; data (def the-users [{:login "deep" :first "Deepthi" :last "Rathore"} {:login "adi" :first "Aditya" :last "Rathore"} {:login "siva" :first "Siva" :last "Jag"} {:login "punit" :first "Punit" :last "Rathore"} {:login "nan" :first "Nanditha" :last "Sunder"}]) (def the-expenses [{:amount 10.0 :merchant "amazon" :category "book" :user "deep"} {:amount 20.0 :merchant "amazon" :category "toy" :user "adi"} {:amount 30.0 :merchant "burger joint" :category "meal" :user "siva"} {:amount 40.0 :merchant "ubuntu" :category "software" :user "punit"} {:amount 50.0 :merchant "sephora" :category "cosmetics" :user "nan"} {:amount 60.0 :merchant "french laundry" :category "meal" :user "deep"} {:amount 70.0 :merchant "nps" :category "school" :user "adi"} {:amount 80.0 :merchant "apple" :category "software" :user "siva"} {:amount 90.0 :merchant "crossword" :category "book" :user "punit"} {:amount 100.0 :merchant "apple" :category "software" :user "nan"} {:amount 110.0 :merchant "alibris" :category "book" :user "deep"} {:amount 120.0 :merchant "toys r us" :category "toy" :user "adi"}]) ;; find-by-merchant ;; filter expenses by merchant ;; Amit's version: (defn find-by-condition ([coll condition filtered] (if (empty? coll) filtered (if (condition (first coll)) (recur (rest coll) condition (conj filtered (first coll))) (recur (rest coll) condition filtered)))) ([coll condition] (find-by-condition coll condition [])) ) (find-by-condition '(1 2 3 4) #(= 0 (mod % 2))) (find-by-condition [1 2 3 4] #(= 0 (mod % 2))) (defn filter-fn [ pred coll ] (if (empty? coll) () (let [f (first coll) r (rest coll)] (if (pred f) (cons f (filter-fn pred r ) ) (recur pred r ) ) ) ) ) (filter-fn #(= \a (first (:login %) )) the-users) (defn find-by-merchant [ expenses merchant ] (let [ match-merchant? (fn [expense] (= ( expense :merchant ) merchant ) ) ] (filter-fn match-merchant? expenses) ) ) (find-by-merchant the-expenses "amazon") (defn find-by-merchant [ expenses merchant ] (filter #(= ( % :merchant ) merchant ) expenses ) ) (find-by-merchant the-expenses "apple") (defn find-by-attribute [ expenses k v ] (filter #(= ( % k ) v ) expenses) ) (find-by-attribute the-expenses :merchant "apple") (find-by-attribute the-expenses :category "book") (defn filter-by-attribute [ k v m ] (= (m k) v) ) (filter (partial filter-by-attribute :merchant "apple" ) the-expenses ) (filter (partial filter-by-attribute :category "book" ) the-expenses ) ;; memoize - takes fn, returns new fn that caches arg/result pairs to improve performance (defn fib-helper [ a b ] (lazy-seq (cons a (fib-helper b (+ a b))) ) ) (defn fib-n [ n ] (take n (fib-helper 0 1)) ) (fib-n 15) ;; 0 1 1 2 3 5 8 (map :login the-users) (defn total ( [coll running ] (if (empty? coll) running (recur (rest coll) (+ running (first coll))))) ( [coll] (total coll 0)) ) (def total (partial reduce + 0)) (total (map :amount the-expenses)) (reduce + 0 (map :amount the-expenses)) (reduce #(+ %1 (:amount %2)) 0 the-expenses) ;; dynamic scope: (def *eval-me* 10) (defn print-the-var [label] (println label *eval-me*)) (print-the-var "A:") (binding [*eval-me* 20] (print-the-var "B:") (binding [*eval-me* 30] (print-the-var "C:")) (print-the-var "D:")) (print-the-var "E:") ;; lexical scope: (def *eval-me* 10) (defn print-the-var [label] (println label *eval-me*)) (print-the-var "A:") (let [*eval-me* 20] (print-the-var "B:") (let [*eval-me* 30] (print-the-var "C:")) (print-the-var "D:")) (print-the-var "E:") ;; java interop ;; (ClassName. constructor-args) ;; (.method object args) ;; (ClassName/method args) ;; (import '(path.to.package Class1 Class2 Class3)) ;; (ns org.corfield ;; (:import '(path.to.package Class1))) ;; (.. (Calendar/getInstance) getTimeZone getDisplayName) ;; (doto object ;; (.method1 args1) ;; (.method2 args2) ;; (.method3 args3)) ;; (bean object) -> map of properties ;; caveat: Java Array is native with alength, aset, sget ;; (proxy [class-or-interface] ;; (method [args] (body)) ;; (method [args] (body))) ;; state and concurrency / multi-threading ;; problems: lost updates, dirty read, unrepeatable reads, phantom read ;; all due to mutable shared state - solution? locking! painful!! ;; transaction failure -> automatic retry with new state ;; synchronous, coordinated -> refs - dosync ;; asynchronous, independent -> agents - send / await ;; synchronous, independent -> atoms - deref / reset! / swap! ;; isolated -> vars - binding (def atomic-users (atom the-users)) (defn add-user [login firstname lastname] (let [new-user { :login login :first firstname :last lastname }] (swap! atomic-users conj new-user) ) ) (add-user "seanc" "Sean" "Corfield") ;; assoc-in m [ key1 key2 key3 ] value -> like m.key1.key2.key3 = value; ;; update-in m [ key1 key2 key3 ] fn -> like m.key1.key2.key3 = fn( m.key1.key2.key3 ); ;; futures - run code in new thread ;; (let [ x (future (code))] ... @x ...) ;; promise - communicate between thread ;; (def p (promise)) ... (deref p) ... @p ... (deliver p value) ;; multimethods ;; (defmulti name dispatch-fn & options ) ;; (defmethod multifn dispatch-value [args] body) - I think there were values? ;; (derive ::dispatch-value ::base-value) - for categories - and Java hierarchies ;; macros! (defn my-unless ([ c t f ] (if c f t)) ([ c t ] (if (not c) t)) ) ;; does not work because args are eval'd *before* passing into my-unless: (my-unless false (println "Hi!")) (my-unless true (println "Bad") (println "Good")) (defmacro unless ([expr form-t form-f] (list 'if expr form-f form-t)) ([expr form] (unless expr form nil)) ) (unless true (println "Bye!")) (unless false (println "Hi!")) (unless true (println "Bad") (println "Good")) ;; using templating: (defmacro unless ([expr form-t form-f] `(if ~expr ~form-f ~form-t)) ([expr form] (unless expr form nil)) ) (unless true (println "Bye!")) (unless false (println "Hi!")) (unless true (println "Bad") (println "Good")) (macroexpand '(unless true (println "Bye!"))) ;; name# - gensym ;; ~`name - force name to be used (in let in macro) (defmacro infix [ l op r ] `(~op ~l ~r)) (infix 1 + 2) (defmacro infix [ [l op r] ] `(~op ~l ~r)) (infix (1 + 2)) ;; destructuring (let [ [a b & more ] '(1 2 3 4 5)] (println a) (println b) (println more) ) (let [ { x :a y :b } { :a 1 :b 2 :c 3 }] (println x) (println y) ) (let [ { :keys [ a c ] } { :a 1 :b 2 :c 3 }] (println a) (println c) ) (defn ac [ { :keys [ a c ] } ] (println "a,c: " a c)) (ac { :a 1 :b 2 :c 3 }) ;; randomly (defmacro randomly [ &body ] (let [n# (count body)] (nth body n#)))