├── doc └── intro.md ├── src ├── learn │ ├── utils │ │ ├── calc │ │ │ ├── fcf.clj │ │ │ └── dcf.clj │ │ └── calculators.clj │ ├── core.clj │ ├── macros │ │ └── basics │ │ │ ├── function_argument_evaluation.clj │ │ │ ├── quoting_tokens.clj │ │ │ ├── macro_expansion.clj │ │ │ └── replace_addition.clj │ ├── chapter05.clj │ ├── chapter06.clj │ ├── chapter04.clj │ └── chapter03.clj └── ideas │ └── stack_overflow.clj ├── .gitignore ├── test └── learn │ └── core_test.clj ├── project.clj ├── CHANGELOG.md ├── LICENSE └── README.md /doc/intro.md: -------------------------------------------------------------------------------- 1 | # Introduction to learn-clojure 2 | 3 | TODO: write [great documentation](http://jacobian.org/writing/what-to-write/) 4 | -------------------------------------------------------------------------------- /src/learn/utils/calc/fcf.clj: -------------------------------------------------------------------------------- 1 | (in-ns 'learn.utils.calculators) 2 | 3 | (defn free-cash-flow [data] 4 | (println "Calculating free cash flow...")) -------------------------------------------------------------------------------- /src/learn/utils/calc/dcf.clj: -------------------------------------------------------------------------------- 1 | (in-ns 'learn.utils.calculators) 2 | 3 | (defn discounted-cash-flow [data] 4 | (println "Calculating discounted cash flow...")) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | pom.xml 5 | pom.xml.asc 6 | *.jar 7 | *.class 8 | /.lein-* 9 | /.nrepl-port 10 | .hgignore 11 | .hg/ 12 | -------------------------------------------------------------------------------- /src/learn/core.clj: -------------------------------------------------------------------------------- 1 | (ns learn.core 2 | (:gen-class)) 3 | 4 | (defn -main 5 | "I don't do a whole lot ... yet." 6 | [& args] 7 | (println "Hello, World!")) 8 | -------------------------------------------------------------------------------- /src/learn/utils/calculators.clj: -------------------------------------------------------------------------------- 1 | (ns learn.utils.calculators 2 | (:gen-class)) 3 | 4 | (load "calc/fcf") 5 | (load "calc/dcf") 6 | 7 | (defn present-value [data] 8 | (println "Calculating present value...")) -------------------------------------------------------------------------------- /test/learn/core_test.clj: -------------------------------------------------------------------------------- 1 | (ns learn.core-test 2 | (:require [clojure.test :refer :all] 3 | [learn.core :refer :all])) 4 | 5 | (deftest a-test 6 | (testing "FIXME, I fail." 7 | (is (= 0 1)))) 8 | -------------------------------------------------------------------------------- /src/learn/macros/basics/function_argument_evaluation.clj: -------------------------------------------------------------------------------- 1 | (ns learn.macros.basics.function-argument-evaluation) 2 | 3 | (comment 4 | (defn print-with-asterisks [printable-argument] 5 | (println "******") 6 | (println printable-argument) 7 | (println "******"))) -------------------------------------------------------------------------------- /src/ideas/stack_overflow.clj: -------------------------------------------------------------------------------- 1 | (ns ideas.stack-overflow) 2 | 3 | (defn any-valid? [x [p & ps :as preds]] 4 | (if-not (empty? preds) 5 | (or (p x) (any-valid? x ps)))) 6 | 7 | (comment 8 | 9 | (defn any-valid? [x [p & ps :as preds]] 10 | (if-not (empty? preds) 11 | (let [res (p x)] 12 | (if-not res 13 | (recur x ps) 14 | res)))) 15 | ) 16 | 17 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject learn-clojure "0.1.0-SNAPSHOT" 2 | :description "Learning Clojure Project" 3 | :url "http://example.com/FIXME" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | :dependencies [[org.clojure/clojure "1.8.0"] 7 | [org.clojure/algo.generic "0.1.2"]] 8 | :main ^:skip-aot learn.core 9 | :target-path "target/%s" 10 | :profiles { 11 | :uberjar {:aot :all} 12 | :user {:plugins [[venantius/ultra "0.5.0"]]} 13 | }) 14 | -------------------------------------------------------------------------------- /src/learn/macros/basics/quoting_tokens.clj: -------------------------------------------------------------------------------- 1 | (ns learn.macros.basics.quoting-tokens) 2 | 3 | 4 | (comment 5 | (class (quote 1)) ; Long 6 | (class (quote 0xFF)) ; Long 7 | (class (quote 017)) ; Long 8 | (class (quote 2r1011)) ; Long 9 | (class (quote 2.78)) ; Double 10 | (class (quote 4.2M)) ; BigDecimal 11 | (class (quote 7N)) ; BigInt 12 | (class (quote 1/2)) ; Ratio 13 | (class (quote "hello")) ; String 14 | (class (quote :name)) ; Keyworkd 15 | (class (quote sum)) ; Symbol 16 | (class (quote map)) ; Symbol 17 | 18 | ) 19 | 20 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). 3 | 4 | ## [Unreleased][unreleased] 5 | ### Changed 6 | - Add a new arity to `make-widget-async` to provide a different widget shape. 7 | 8 | ## [0.1.1] - 2016-12-24 9 | ### Changed 10 | - Documentation on how to make the widgets. 11 | 12 | ### Removed 13 | - `make-widget-sync` - we're all async, all the time. 14 | 15 | ### Fixed 16 | - Fixed widget maker to keep working when daylight savings switches over. 17 | 18 | ## 0.1.0 - 2016-12-24 19 | ### Added 20 | - Files from the new template. 21 | - Widget maker public API - `make-widget-sync`. 22 | 23 | [unreleased]: https://github.com/your-name/learn-clojure/compare/0.1.1...HEAD 24 | [0.1.1]: https://github.com/your-name/learn-clojure/compare/0.1.0...0.1.1 25 | -------------------------------------------------------------------------------- /src/learn/macros/basics/macro_expansion.clj: -------------------------------------------------------------------------------- 1 | (ns learn.macros.basics.macro-expansion) 2 | 3 | (comment 4 | 5 | (macroexpand-1 '(when (= 1 2) (println "Math is broken"))) 6 | ;;expands to: (if (= 1 2) (do (println "Math is broken"))) 7 | 8 | ;;buy what if the macro starts with another macro 9 | 10 | (defmacro when-falsy [test & body] 11 | (list 'when (list 'not test) 12 | (cons 'do body))) 13 | 14 | (when-falsy (= 1 2) (println "Math is not broken")) 15 | 16 | ;; if we do macroexpand-1 17 | (macroexpand-1 '(when-falsy (= 1 2) (println "Math is not broken"))) 18 | 19 | ;; we get an expression that starts with a another macro 20 | ;; (when (not (= 1 2)) (do (println "Math is not broken"))) 21 | 22 | ;;but if we do macroexpand instead 23 | (macroexpand '(when-falsy (= 1 2) (println "Math is not broken"))) 24 | 25 | ;;we get the full expansion 26 | ;; (if (not (= 1 2)) (do (do (println "Math is not broken")))) 27 | ) -------------------------------------------------------------------------------- /src/learn/macros/basics/replace_addition.clj: -------------------------------------------------------------------------------- 1 | (ns learn.macros.basics.replace-addition) 2 | 3 | (comment 4 | ;; There are two phases: read and eval 5 | ;; We can get in the middle of reading to change 6 | ;; the output data structures before they are evaled. 7 | 8 | (let [expression (read-string "(+ 1 2 3 4 5)")] 9 | (let [changed (cons (read-string "*") 10 | (rest expression))] 11 | (eval changed))) 12 | 13 | ;; We cannot simply type the expression (+ 1 2 3 4 5) 14 | ;; because it would be evaulated right away, so to 15 | ;; suppress the evaluation of a list we must quote it. 16 | 17 | (let [expression (quote (+ 1 2 3 4 5))] 18 | (let [changed (cons (quote *) 19 | (rest expression))] 20 | (eval changed)))) 21 | 22 | (comment 23 | 24 | ;; there ia reader macro to simplify quoting 25 | (let [expression '(+ 1 2 3 4 5)] 26 | (let [changed (cons '* (rest expression))] 27 | (eval changed)))) 28 | 29 | -------------------------------------------------------------------------------- /src/learn/chapter05.clj: -------------------------------------------------------------------------------- 1 | (ns learn.chapter05 2 | (:import (java.util Random Calendar TimeZone) 3 | (java.text SimpleDateFormat) 4 | (java.io File FileFilter) 5 | (java.awt.event MouseAdapter))) 6 | 7 | 8 | ;; There are multiple ways to invoke Java methods 9 | 10 | ;; Example #1 11 | (defn date-from-string-1 [date-string] 12 | (let [sdf (new SimpleDateFormat "yyyy-MM-dd")] 13 | (.parse sdf date-string))) 14 | 15 | ;; Example #2 16 | (defn date-from-string-2 [date-string] 17 | (let [sdf (new SimpleDateFormat "yyyy-MM-dd")] 18 | (. sdf parse date-string))) 19 | 20 | ;; Example #3 21 | (defn date-from-string-3 [date-string] 22 | (let [sdf (new SimpleDateFormat "yyyy-MM-dd")] 23 | (. sdf (parse date-string)))) 24 | 25 | 26 | ;; Java Syntax can be verbose 27 | ;; Consider getting the time zone name 28 | 29 | ;; Example 1 30 | (defn time-zone-name [] 31 | (. (. (Calendar/getInstance) (getTimeZone)) (getDisplayName))) 32 | 33 | ;; Example 2: Simplified notation 34 | (defn time-zone-name [] 35 | (. (. (Calendar/getInstance) getTimeZone) getDisplayName)) 36 | 37 | ;; Example 3: Using double dot notation 38 | (defn time-zone-name [] 39 | (.. (Calendar/getInstance) (getTimeZone) (getDisplayName))) 40 | 41 | ;; Example 4: Double dot with simplified notation 42 | (defn time-zone-name [] 43 | (.. (Calendar/getInstance) getTimeZone getDisplayName)) 44 | 45 | ;;Consider the more elaborate example 46 | (defn time-zone-short-name [] 47 | (.. (Calendar/getInstance) getTimeZone (getDisplayName true TimeZone/SHORT))) 48 | 49 | 50 | (defn the-past-midnight-1 [] 51 | (let [calendar (Calendar/getInstance)] 52 | (.set calendar Calendar/AM_PM Calendar/AM) 53 | (.set calendar Calendar/HOUR 0) 54 | (.set calendar Calendar/MINUTE 0) 55 | (.set calendar Calendar/SECOND 0) 56 | (.set calendar Calendar/MILLISECOND 0) 57 | (.getTime calendar))) 58 | 59 | ;; a better way to do the previous thing is 60 | 61 | (defn the-past-midnight-2 [] 62 | (let [calendar (Calendar/getInstance)] 63 | (doto calendar 64 | (.set Calendar/AM_PM Calendar/AM) 65 | (.set Calendar/HOUR 0) 66 | (.set Calendar/MINUTE 0) 67 | (.set Calendar/SECOND 0) 68 | (.set Calendar/MILLISECOND 0)) 69 | (.getTime calendar))) 70 | 71 | (defn get-string-bytes-1 [strings] 72 | (map (fn [s] (.getBytes s)) strings)) 73 | 74 | (defn get-string-bytes-2 [strings] 75 | (map #(.getBytes %) strings)) 76 | 77 | (defn get-string-bytes-3 [strings] 78 | (map (fn [^String s] (.getBytes s)) strings)) 79 | 80 | (defn get-string-bytes-4 [strings] 81 | (map (memfn ^String getBytes) strings)) 82 | 83 | (def my-subseq (memfn ^String subSequence ^Long start ^Long end)) 84 | 85 | 86 | ;; IMPLEMENTING INTERFACES AND EXTENDING CLASSES 87 | 88 | (defn create-mouse-adapter [] 89 | (proxy [MouseAdapter] [] 90 | (mousePressed 91 | [event] 92 | (println "Hey!")))) 93 | 94 | (comment 95 | ;; which you could invoke by doing 96 | (. (create-mouse-adapter) (mousePressed nil)) 97 | ) 98 | 99 | (def my-filter 100 | (reify FileFilter 101 | (accept [this f] 102 | (.isDirectory f)))) 103 | 104 | (comment 105 | ;;which I could invoke as 106 | (. my-filter (accept (File. "."))) ;; yields true 107 | ) 108 | 109 | -------------------------------------------------------------------------------- /src/learn/chapter06.clj: -------------------------------------------------------------------------------- 1 | (ns learn.chapter06) 2 | 3 | ;;;;;;;;;;;;;;;;;;;;;;; 4 | ;; USING REFS 5 | ;;;;;;;;;;;;;;;;;;;;;;; 6 | 7 | (def all-users (ref {})) 8 | 9 | (comment 10 | 11 | ;; You can dereference the ref in two ways 12 | (deref all-users) 13 | 14 | ;;using a reader macro 15 | @all-users 16 | ) 17 | 18 | ;;MUTATING REFERENCES: ref-set, alter or commute 19 | 20 | ;; Since refs are meant for situations where multiple threads 21 | ;; need to coordiante changes, the Clojure runtime demands that 22 | ;; mutating a ref be done inside a STM transaction. 23 | 24 | (dosync (ref-set all-users {})) 25 | 26 | ;; Typically, a ref is mutated by taking its current value, 27 | ;; applying a function to it, and storing the new value back into it. 28 | 29 | (defn new-user [id login monthly-budget] 30 | {:id id :login login :montly-budge monthly-budget :total-expenses 0}) 31 | 32 | (defn add-new-user-1 [login budget-amount] 33 | (dosync 34 | (let [current-number (count @all-users) 35 | user (new-user (inc current-number) login budget-amount)] 36 | (alter all-users assoc login user)))) 37 | 38 | (defn add-new-user-2 [login budget-amount] 39 | (dosync 40 | (let [current-number (count @all-users) 41 | user (new-user (inc current-number) login budget-amount)] 42 | (commute all-users assoc login user)))) 43 | 44 | 45 | ;;;;;;;;;;;;;;;;;;;;;;; 46 | ;; AGENTS 47 | ;;;;;;;;;;;;;;;;;;;;;;; 48 | 49 | ;; creating the agent 50 | (def total-cpu-time (agent 0)) 51 | 52 | (comment 53 | ;; we can use the same mechanisms to dereference an agent 54 | (deref total-cpu-time) 55 | @total-cpu-time 56 | ) 57 | 58 | ;; mutating agents with send and send-off 59 | 60 | ;; Changes made to the agent will happen asynchronously. 61 | ;; These changes are made by sending an action function to the agent. 62 | ;; which runs it on a separate thread at a later time. 63 | 64 | (defn increase-cpu-time-1 [time] 65 | (send total-cpu-time + time)) 66 | 67 | 68 | ;; send will use an event loop to make sure only one action 69 | ;; at the time runs on the agent, therefore we cannot do 70 | ;; blocking operations on the agent, for that matter we have send-off 71 | 72 | (defn sum-it [a b] 73 | (Thread/sleep 10000) 74 | (+ a b)) 75 | 76 | (defn increase-cpu-time-2 [time] 77 | (send-off total-cpu-time sum-it time)) 78 | 79 | (comment 80 | ;; if we need to wait for a given action to complete 81 | ;; we can use await for that matter, as way to turn 82 | ;; asynchronous code into a synchronous code again. 83 | 84 | (await total-cpu-time) ;; this will block until done! 85 | (await-for 1000 total-cpu-time) ;;waits at most 1000 ms. 86 | 87 | ) 88 | 89 | (def bad-agent (agent 100)) 90 | 91 | (comment 92 | (send bad-agent / 0) ;;sends a message that will surely fail 93 | (println @bad-agent) ;; yields the last consistent value 100 94 | 95 | ;; if we try to send any further message it will fail with its 96 | ;; latest exception thrown 97 | (send bad-agent / 2) ;;yields ArithmeticException: Divide by zero 98 | (agent-error bad-agent) ;; gets the exception thrown 99 | 100 | ;; to make the agent usable again, we must clear the errors 101 | (clear-agent-errors bad-agent) 102 | (send bad-agent / 2) ;;now this succeeds 103 | ) 104 | 105 | ;;;;;;;;;;;;;;;;;; 106 | ;; ATOMS 107 | ;;;;;;;;;;;;;;;;;; 108 | 109 | (def total-rows (atom 0)) 110 | 111 | (comment 112 | 113 | ;; You can dereference the ref in two ways 114 | (deref total-rows) 115 | 116 | ;;using a reader macro 117 | @total-rows) 118 | 119 | 120 | (reset! total-rows 10) 121 | (swap! total-rows + 100) 122 | 123 | ;;;;;;;;;;;;;;;;;; 124 | ;; VARS 125 | ;;;;;;;;;;;;;;;;;; 126 | (comment 127 | (def ^:dynamic *mysql-host*) 128 | 129 | (defn db-query [db] 130 | (binding [*mysql-host*] 131 | (count *mysql-host*))) 132 | 133 | (def mysql-hosts ["test-mysql" "dev-mysql" "stagin-mysql"]) 134 | (pmap db-query mysql-hosts)) 135 | 136 | ;;;;;;;;;;;;;;;;;; 137 | ;; WATCHERS 138 | ;;;;;;;;;;;;;;;;;; 139 | 140 | (comment 141 | (defn on-change [the-key the-ref old-val new-val] 142 | (println "Just saw change from " old-val " to " new-val)) 143 | 144 | (add-watch total-rows :total-watcher on-change) 145 | (swap! total-rows inc) 146 | (remove-watch total-rows :total-watcher)) 147 | 148 | ;;;;;;;;;;;;;;;;;; 149 | ;; FUTURES 150 | ;;;;;;;;;;;;;;;;;; 151 | 152 | (defn long-calculation [a b] 153 | (Thread/sleep 5000) 154 | (* a b)) 155 | 156 | (defn long-run [] 157 | (let [x (long-calculation 11 13) 158 | y (long-calculation 13 17) 159 | z (long-calculation 17 19)] 160 | (* x y z))) 161 | 162 | (defn fust-run [] 163 | (let [x (future (long-calculation 11 13)) 164 | y (future (long-calculation 13 17)) 165 | z (future (long-calculation 17 19))] 166 | (* @x @y @z))) 167 | 168 | (defn with-promise [] 169 | (let [p (promise)] 170 | (future (Thread/sleep 5000) 171 | (deliver p :done)) 172 | @p)) 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /src/learn/chapter04.clj: -------------------------------------------------------------------------------- 1 | (ns learn.chapter04 2 | (:require [clojure.algo.generic.math-functions :as math :refer :all])) 3 | 4 | (defn ad-hoc-type-name [thing] 5 | (condp = (type thing) 6 | java.lang.String "String" 7 | clojure.lang.PersistentVector "Vector")) 8 | 9 | (def type-name-implementations 10 | {java.lang.String (fn [thing] "String") 11 | clojure.lang.PersistentVector (fn [thing] "Vector")}) 12 | 13 | (defn open-ad-hoc-type-name [thing] 14 | (let [dispatch-value (type thing)] 15 | (if-let [implementation (get type-name-implementations dispatch-value)] 16 | (implementation thing) 17 | (throw (IllegalArgumentException. (str "No implementation found for " dispatch-value)))))) 18 | 19 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 20 | ;; POLYMORPHISM AND MULTIMETHODS 21 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 22 | 23 | (def example-user {:login "rob" :referrer "mint.com" :salary 100000}) 24 | 25 | (defn fee-amount 26 | "Calculates the fee you pay to affiliates based on their annual salary" 27 | [percentage user] 28 | (with-precision 16 :rounding HALF_EVEN 29 | (* 0.01M percentage (:salary user)))) 30 | 31 | (comment 32 | 33 | (defn affiliate-fee 34 | "Calculates the fee for an affiliate user based on their referrer and annual salary" 35 | [user] 36 | ;;this is an example of close dispatch 37 | ;;where the referrer is the dispatch criteria 38 | ;;the problem is that adding referrers requires code changes 39 | (case (:referrer user) 40 | "google.com" (fee-amount 0.01M user) 41 | "mint.com" (fee-amount 0.03M user) 42 | (fee-amount 0.02M user)))) 43 | 44 | 45 | 46 | ;;MULTIMETHODS TO THE RESCUE! 47 | 48 | (comment 49 | ;;multimethod defines dispatch criteria 50 | 51 | (defmulti affiliate-fee 52 | (fn [user] (:referrer user))) ;;this is equivalent to just using :referrer 53 | 54 | ;; implementation of the multimethod 55 | 56 | (defmethod affiliate-fee "mint.com" 57 | [user] (fee-amount 0.03M user)) 58 | 59 | (defmethod affiliate-fee "google.com" 60 | [user] (fee-amount 0.01M user)) 61 | 62 | (defmethod affiliate-fee :default 63 | [user] (fee-amount 0.02M user))) 64 | 65 | 66 | 67 | ;;the default method can also be defined in the dispatch 68 | 69 | (defmulti affiliate-fee :referrer :default "*") 70 | 71 | (defmethod affiliate-fee "mint.com" 72 | [user] (fee-amount 0.03M user)) 73 | 74 | (defmethod affiliate-fee "google.com" 75 | [user] (fee-amount 0.01M user)) 76 | 77 | (defmethod affiliate-fee "*" 78 | [user] (fee-amount 0.02M user)) 79 | 80 | ;;MULTIPLE DISPATCH 81 | 82 | (def user-1 {:login "rob" :referrer "mint.com" :salary 100000 :rating :rating/bronze}) 83 | (def user-2 {:login "gordon" :referrer "mint.com" :salary 80000 :rating :rating/silver}) 84 | (def user-3 {:login "kyle" :referrer "google.com" :salary 90000 :rating :rating/gold}) 85 | (def user-4 {:login "celeste" :referrer "yahoo.com" :salary 70000 :rating :rating/platinum}) 86 | 87 | ;----------------------------------------------------- 88 | ; Affiliate Profit Rating Fee (% of salary) 89 | ;----------------------------------------------------- 90 | ; mint.com Bronze 0.03 91 | ; mint.com Silver 0.04 92 | ; mint.com Gold/Platinum 0.05 93 | ; google.com Gold/Platinum 0.03 94 | ;----------------------------------------------------- 95 | 96 | (comment) 97 | 98 | ;; the fee category will be our new dispatch function 99 | (defn fee-category [user] 100 | [(:referrer user) (:rating user)]) 101 | 102 | (defmulti profit-based-affiliate-fee fee-category) 103 | 104 | (defmethod profit-based-affiliate-fee ["mint.com" :rating/bronze] 105 | [user] (fee-amount 0.03M user)) 106 | 107 | (defmethod profit-based-affiliate-fee ["mint.com" :rating/silver] 108 | [user] (fee-amount 0.04M user)) 109 | 110 | ;; notice that these two methods are the same thing 111 | ;; this looks like ad hoc polymorphism 112 | ;; a hint that these two are the same 113 | ;; perhaps this a job for subtype polymorphism 114 | (defmethod profit-based-affiliate-fee ["mint.com" :rating/gold] 115 | [user] (fee-amount 0.05M user)) 116 | 117 | (defmethod profit-based-affiliate-fee ["mint.com" :rating/platinum] 118 | [user] (fee-amount 0.05M user)) 119 | 120 | ;; notice that these two other methods are the same thing 121 | ;; this looks like ad hoc polymorphism 122 | ;; a hint that these two are the same 123 | ;; perhaps this a job for subtype polymorphism 124 | (defmethod profit-based-affiliate-fee ["google.com" :rating/gold] 125 | [user] (fee-amount 0.03M user)) 126 | 127 | (defmethod profit-based-affiliate-fee ["google.com" :rating/platinum] 128 | [user] (fee-amount 0.03M user)) 129 | 130 | (defmethod profit-based-affiliate-fee :default 131 | [user] (fee-amount 0.02M user)) 132 | 133 | 134 | 135 | ;;MULTIPLE DISPATCH AND SUBTYPE POLYMORPHISM 136 | 137 | ; 138 | ; ┌────────┐ 139 | ; │ Profit │ 140 | ; │ Rating │ 141 | ; └────────┘ 142 | ; ^ 143 | ; | 144 | ; +------------+------------+ 145 | ; | | 146 | ; ┌────────┐ ┌────────┐ 147 | ; │ Basic │ │Premier │ 148 | ; └────────┘ └────────┘ 149 | ; ^ ^ 150 | ; | | 151 | ; +------+-----+ +-----+------+ 152 | ; | | | | 153 | ; ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ 154 | ; │ Bronze │ │ Silver │ │ Gold │ │Platinum│ 155 | ; └────────┘ └────────┘ └────────┘ └────────┘ 156 | 157 | ;; USING DERIVE TO CREATE THE HIERARCHY 158 | ;; derive x from y (i.e. x is a kind of y) 159 | 160 | (derive :rating/bronze :rating/basic) 161 | (derive :rating/silver :rating/basic) 162 | (derive :rating/gold :rating/premier) 163 | (derive :rating/platinum :rating/premier) 164 | (derive :rating/basic :rating/ANY) 165 | (derive :rating/premier :rating/ANY) 166 | 167 | (isa? :rating/bronze :rating/basic) ;;yields true 168 | (parents :rating/god) ;;yields :rating/premier 169 | (ancestors :rating/bronze) ;; yields #{:rating/ANY :rating/basic} 170 | (descendants :rating/basic) ;;yields #{:rating/bronze :rating/silver} 171 | 172 | (defmulti greet-user :rating) 173 | 174 | (defmethod greet-user :rating/basic 175 | [user] (str "Hello " (:login user) ".")) 176 | 177 | (defmethod greet-user :rating/premier 178 | [user] (str "Welcome, " (:login user) ", valued affiliate member!")) 179 | 180 | (comment 181 | ;;if now we do this, we can see the the multimethod criteria 182 | ;;takes into accout the hierarchical aspect to determine dispatch method 183 | (map c4/greet-user [c4/user-1 c4/user-2 c4/user-3 c4/user-4])) 184 | 185 | 186 | 187 | ;; the fee category will be our new dispatch function 188 | (defn fee-category [user] 189 | [(:referrer user) (:rating user)]) 190 | 191 | (defmulti profit-based-affiliate-fee fee-category) 192 | 193 | (defmethod profit-based-affiliate-fee ["mint.com" :rating/bronze] 194 | [user] (fee-amount 0.03M user)) 195 | 196 | (defmethod profit-based-affiliate-fee ["mint.com" :rating/silver] 197 | [user] (fee-amount 0.04M user)) 198 | 199 | (defmethod profit-based-affiliate-fee ["mint.com" :rating/premier] 200 | [user] (fee-amount 0.05M user)) 201 | 202 | 203 | (defmethod profit-based-affiliate-fee ["google.com" :rating/premier] 204 | [user] (fee-amount 0.03M user)) 205 | 206 | (comment 207 | ;;this default would not work now 208 | (defmethod profit-based-affiliate-fee :default 209 | [user] (fee-amount 0.02M user))) 210 | 211 | 212 | 213 | (defmulti size-up (fn [observer observed] 214 | [(:rating observer) (:rating observed)])) 215 | 216 | (defmethod size-up [:rating/platinum :rating/ANY] 217 | [_ observed] (str (:login observed) " seems scrawny.")) 218 | 219 | (defmethod size-up [:rating/ANY :rating/platinum] 220 | [_ observed] (str (:login observed) " shimmers with unearthly light.")) 221 | 222 | (comment 223 | 224 | ;;the following invocation would cause ambiguties unless we use a prefer method 225 | (size-up {:rating :rating/platinum} user-4) 226 | 227 | ;;prefer the first dispatch over the second one 228 | (prefer-method size-up [:rating/ANY :rating/platinum] 229 | [:rating/platinum :rating/ANY])) 230 | 231 | 232 | 233 | (comment 234 | 235 | ;; since the clojure generic math function uses multimethods for its definitions 236 | ;; I can take their pow function that works on doubles and make an implementation 237 | ;; that works on longs, and voila, it now works pefectly 238 | 239 | (defmethod math/pow [java.lang.Long java.lang.Long] 240 | [x y] (long (Math/pow x y))) 241 | 242 | ;;just testing imports and dependencies 243 | (defn my-pow [x y] 244 | (math/pow x y))) 245 | 246 | 247 | 248 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;; 249 | ;; USER-DEFINED HIERARCHIES 250 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;; 251 | 252 | (def my-hierarchy (make-hierarchy)) 253 | (derive my-hierarchy :a :letter) ;; Meaning :a is a :letter 254 | (def my-hierarchy 255 | (-> my-hierarchy 256 | (derive :a :letter) 257 | (derive :b :letter) 258 | (derive :c :letter))) 259 | 260 | (isa? my-hierarchy :a :letter) ;;yields true 261 | (isa? my-hierarchy :d :letter) ;;yields false 262 | (parents my-hierarchy :a) ;; yields #{:letter} 263 | (descendants my-hierarchy :letter) ;;yields #{:a :b :c} 264 | 265 | (defmulti letter? identity :hierarchy #'my-hierarchy) 266 | (defmethod letter? :letter 267 | [_] true) 268 | 269 | 270 | 271 | 272 | 273 | -------------------------------------------------------------------------------- /src/learn/chapter03.clj: -------------------------------------------------------------------------------- 1 | (ns learn.chapter03) 2 | 3 | ;;;;;;;;;;;;;;;;;;;;;;;;;;; 4 | ;; METADATA 5 | ;;;;;;;;;;;;;;;;;;;;;;;;;;; 6 | 7 | (comment 8 | 9 | ;; there's a better way with the reader macro: ^{} 10 | (def untrusted 11 | (with-meta {:command "delete-table" :subject "users"} 12 | {:safe false :io true}))) 13 | 14 | 15 | (def untrusted ^{:safe false :io true :retry 1} 16 | {:command "delete-table" :subject "users"}) 17 | 18 | (comment 19 | ;; to see the contents of the metadata you do 20 | (meta untrusted)) ;;{:safe false :io true :retry 1} 21 | 22 | 23 | ;; when new values are created out of old ones 24 | ;; the metadata is still kept in the new structure 25 | ;; do a (meta still-untrusted) to see it 26 | (def still-untrusted (assoc untrusted :complete? false)) 27 | 28 | ;; functions can also have meta data 29 | (defn ^{:safe true :console true :doc "Testing meta in functions"} 30 | testing-meta [] 31 | (println "Hello from meta!")) 32 | 33 | (comment 34 | ;; in order to see the metadata of a function you need to 35 | ;; look into its var, since metadata is stored in the var 36 | ;; and not in the function itself 37 | (meta (var testing-meta)) 38 | 39 | ;; alternatively 40 | (meta #'testing-meta)) 41 | 42 | 43 | ;; metadata can be used with type parameters to provide 44 | ;; JAVA TYPE HITS!!!! 45 | (defn string-length [^String s] 46 | (.length s)) 47 | 48 | (comment 49 | ;; if you want the compiler to let you know of the importance 50 | ;; of these type annotations turn on reflection warnings in code 51 | (set! *warn-on-reflection* true)) 52 | 53 | 54 | (comment 55 | ;; you can see the metadata of the arguments as well 56 | ;; {:arglist ([s]) ...} 57 | (-> (meta #'string-length) 58 | (:arglists) 59 | (first) 60 | (first) 61 | (meta)) ;;yields {:tag String} 62 | 63 | ;;alternatively 64 | (meta (first (first (:arglist (meta #'string-length)))))) 65 | 66 | 67 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;; 68 | ;; ARRAYS OF SPECIFIC TYPES 69 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;; 70 | 71 | (defn array-type [kclass] 72 | (.getName (class (make-array kclass 0)))) 73 | 74 | (comment 75 | 76 | (array-type BigDecimal)) 77 | 78 | ;; yields [Ljava.math.BigDecimal] 79 | ;; which is the JVM notation for an object array of tye BigDecimal 80 | 81 | 82 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;; 83 | ;; EXCEPTIONS 84 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;; 85 | 86 | (defn safe-average [numbers] 87 | (let [total (apply + numbers)] 88 | (try 89 | (/ total (count numbers)) 90 | (catch ArithmeticException e 91 | (println "Divided by zero!") 92 | 0)))) 93 | 94 | 95 | (defn complex-average [numbers] 96 | (let [total (apply + numbers)] 97 | (try 98 | (println "Attempting division...") 99 | (/ total (count numbers)) 100 | (catch ArithmeticException e "DIVIDE BY ZERO!") 101 | (catch RuntimeException e "Runtime exception!") 102 | (catch Throwable e "Unknown exception encountered!") 103 | (finally (println "done."))))) 104 | 105 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;; 106 | ;; FUNCTIONS 107 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;; 108 | 109 | ;; Functions may have multiple arities 110 | (defn total-cost 111 | 112 | "Determines cost of goods of a number of items of a given price" 113 | 114 | ([item-cost number-of-items] 115 | (* item-cost number-of-items)) 116 | 117 | ([item-cost] 118 | (total-cost item-cost 1))) 119 | 120 | ;; You can define precondition and postconditions 121 | (defn item-total [price quantity discount-percentage] 122 | {:pre [(> price 0) (> quantity 0)] 123 | :post [(> % 0)]} 124 | (->> (/ discount-percentage 100) 125 | (- 1) 126 | (* price quantity) 127 | float)) 128 | 129 | (comment 130 | (item-total 100 2 0) ;;yields 200.0 131 | (item-total 100 2 10) ;;yields 180.0 132 | (item-total 100 -2 10) ;;AssertionError for precondition 133 | (item-total 100 2 110)) ;;Assertion for postcondition (BUG!!!) 134 | 135 | 136 | 137 | ;; Variadic functions 138 | (defn total-all-numbers [& numbers] 139 | (apply + numbers)) 140 | 141 | (comment 142 | ;; now we can invoke the function as 143 | (total-all-numbers) 144 | (total-all-numbers 1) 145 | (total-all-numbers 1 2) 146 | (total-all-numbers 1 2 3) 147 | (total-all-numbers 1 2 3 4) 148 | (total-all-numbers 1 2 3 4 5)) ;... 149 | 150 | 151 | (defn many-arities 152 | ([] 0) 153 | ([a] 1) 154 | ([a b c] 3) 155 | ([a b c & more] "variadic")) 156 | 157 | ;; CLASSICAL RECURSION 158 | (defn count-down [n] 159 | (when-not (zero? n) 160 | (when (zero? (rem n 100)) 161 | (println "count-down:" n)) 162 | (count-down (dec n)))) 163 | 164 | (defn quicksort [xs] 165 | (if (not-empty xs) 166 | (let [x (first xs) 167 | xs (rest xs) 168 | ls (quicksort (filter #(< % x) xs)) 169 | rs (quicksort (filter #(> % x) xs))] 170 | (concat ls [x] rs)))) 171 | 172 | 173 | ;; TAIL RECURSION 174 | (defn count-downr [n] 175 | (when-not (zero? n) 176 | (if (zero? (rem n 100)) 177 | (println "count-down:" n)) 178 | (recur (dec n)))) 179 | 180 | ;; MUTUALLY RECURSIVE 181 | (comment 182 | 183 | (declare is-odd?) 184 | 185 | (defn is-even? [n] 186 | (if (zero? n) 187 | true 188 | (is-odd? (dec n)))) 189 | 190 | (defn is-odd? [n] 191 | (if (zero? n) 192 | false 193 | (is-even? (dec n))))) 194 | 195 | 196 | ;; TAIL MUTUALLY RECURSIVE 197 | (comment 198 | (declare my-is-odd?) 199 | 200 | (defn- my-is-even? [n] 201 | (if (zero? n) 202 | true 203 | (fn [](my-is-odd? (dec n))))) 204 | 205 | (defn- my-is-odd? [n] 206 | (if (zero? n) 207 | false 208 | (fn [] (my-is-even? (dec n))))) 209 | 210 | (comment 211 | (trampoline is-odd? 5) 212 | (trampoline is-even? 4)) 213 | 214 | 215 | (def is-even? (partial trampoline my-is-even?)) 216 | (def is-odd? (partial trampoline my-is-odd?))) 217 | 218 | 219 | 220 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;; 221 | ;; SCOPE RULES 222 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;; 223 | 224 | (comment 225 | ;; “Vars in Clojure are, in some ways, similar to globals in other languages. 226 | ;; Vars are defined at the top level of any namespace, using the def special form. 227 | 228 | (def MAX-CONNECTIONS 10) ;;bound var 229 | (def ^:dynamic RABBITMQ-CONNECTION) ;;unbound var 230 | 231 | (binding [RABBITMQ-CONNECTION (new-connection)] 232 | ()) 233 | ;; do something with rabbit mq connection here 234 | 235 | 236 | (defn *db-host* "localhost") 237 | 238 | (defn expense-report [start-date end-date] 239 | (println *db-host*)) ;;do real work here 240 | 241 | ;; by changing your bindings you can test you code 242 | ;; locally or just as easily move it to production 243 | 244 | (binding [*db-host* "production"] 245 | (expense-report "2010-01-01" "2010-01-07"))) 246 | 247 | 248 | 249 | ;; DYNAMIC BINDING 250 | 251 | (comment 252 | 253 | ;; through manual bindings you control 254 | ;; the values of your vars at runtime 255 | 256 | (def ^:dynamic *eval-me* 10) 257 | (defn print-the-var [label] 258 | (println label *eval-me*)) 259 | 260 | (defn my-binding-demo [] 261 | (print-the-var "A:") 262 | (binding [*eval-me* 20] 263 | (print-the-var "B:") 264 | (binding [*eval-me* 30] 265 | (print-the-var "C:")) 266 | (print-the-var "D:")) 267 | (print-the-var "E:"))) 268 | 269 | 270 | 271 | ;; USING DYNAMIC BINDING FOR AOP PROGRAMMING STYLE 272 | 273 | (comment 274 | 275 | (defn ^:dynamic twice [x] 276 | (println "Original Function") 277 | (* x x)) 278 | 279 | (defn call-twice [y] 280 | (twice y)) 281 | 282 | (defn with-log [f log-entry] 283 | (fn [& args] 284 | (println log-entry) 285 | (apply f args))) 286 | 287 | (binding [twice (with-log twice "Calling the twice function")] 288 | (call-twice 20))) 289 | 290 | 291 | 292 | (comment 293 | ;; a classical mistake with dynamic binding 294 | 295 | (def ^:dynamic *factor* 10) 296 | (defn multiply [x] 297 | (* x *factor*)) 298 | 299 | (map multiply [1 2 3 4 5]) ;;in console yields [10 20 30 40 50] 300 | 301 | (binding [*factor* 20] 302 | (map multiply [1 2 3 4 5])) 303 | 304 | ;; still yields [10 20 30 40 50] in console 305 | ;; because printing happens after binding is done 306 | ;; and map is a lazy sequence 307 | 308 | ;;we can either do 309 | 310 | (binding [*factor* 20] 311 | (apply println (map multiply [1 2 3 4 5]))) 312 | 313 | (binding [*factor* 20] 314 | (doall (map multiply [1 2 3 4 5])))) 315 | 316 | 317 | 318 | 319 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;; 320 | ;; DESTRUCTURING 321 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;; 322 | (comment 323 | 324 | ;; This function can be better written 325 | (defn describe-salary [person] 326 | (let [first (:first-name person) 327 | last (:last-name person) 328 | annual (:salary person)] 329 | (println first last "earns" annual))) 330 | 331 | ;(require '[learn.chapter03 :as chap :refer [describe-salary]] :reload) 332 | 333 | (defn describe-salary [{first :first-name 334 | last :last-name 335 | annual :salary}] 336 | (println first last "earns" annual)) 337 | 338 | ;;provide optional paramters 339 | (defn describe-salary [{first :first-name 340 | last :last-name 341 | annual :salary 342 | bonus :bonus-percentage 343 | :or {bonus 5}}] 344 | (println first last "earns" annual "with a bonus of" bonus)) 345 | 346 | ;;gain access to the entire map 347 | (defn describe-salary [{first :first-name 348 | last :last-name 349 | annual :salary 350 | bonus :bonus-percentage 351 | :or {bonus 5} 352 | :as p}] 353 | (println first last "earns" annual "with a bonus of" bonus) 354 | (println "And also the full map is" p)) 355 | 356 | 357 | (describe-salary {:first-name "Edwin" :last-name "Dalorzo" :salary 100}) 358 | (describe-salary {:first-name "Karla" :last-name "Fallas" :salary 100 :bonus-percentage 50}) 359 | 360 | ;;simplify key usage 361 | (defn greet-user [{:keys [first-name last-name]}] 362 | (println "Welcome," first-name last-name)) 363 | 364 | (greet-user {:first-name "Edwin" :last-name "Dalorzo"})) 365 | 366 | 367 | 368 | 369 | 370 | (comment 371 | 372 | ;;with vectors 373 | 374 | (defn print-amounts [[amount-1 amount-2]] 375 | (println "Amounts are" amount-1 amount-2)) 376 | 377 | (print-amounts [30.39 31.45]) 378 | 379 | (defn print-amount-multiple [[amount-1 amount-2 & remaining]] 380 | (println "Amounts are" amount-1 amount-2 "and" remaining)) 381 | 382 | (print-amount-multiple [10.95 31.45 22.36 2.95]) 383 | 384 | (defn print-amount-multiple [[amount-1 amount-2 & remaining :as all]] 385 | (println "Amounts are" amount-1 amount-2 "and" remaining) 386 | (println "Also, all the amounts are" all)) 387 | 388 | (print-amount-multiple [10.95 31.45 22.36 2.95]) 389 | 390 | 391 | ;;nested vectors 392 | (defn print-first-category [[[category amount] & _]] 393 | (println "First category was:" category) 394 | (println "First amount was:" amount)) 395 | 396 | (print-first-category [[:books 49.95] [:coffee 4.95] [:caltrain 2.25]])) 397 | 398 | (defn greeting 399 | [name] 400 | (str "Hello, " name "!")) 401 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 2 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 3 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 4 | 5 | 1. DEFINITIONS 6 | 7 | "Contribution" means: 8 | 9 | a) in the case of the initial Contributor, the initial code and 10 | documentation distributed under this Agreement, and 11 | 12 | b) in the case of each subsequent Contributor: 13 | 14 | i) changes to the Program, and 15 | 16 | ii) additions to the Program; 17 | 18 | where such changes and/or additions to the Program originate from and are 19 | distributed by that particular Contributor. A Contribution 'originates' from 20 | a Contributor if it was added to the Program by such Contributor itself or 21 | anyone acting on such Contributor's behalf. Contributions do not include 22 | additions to the Program which: (i) are separate modules of software 23 | distributed in conjunction with the Program under their own license 24 | agreement, and (ii) are not derivative works of the Program. 25 | 26 | "Contributor" means any person or entity that distributes the Program. 27 | 28 | "Licensed Patents" mean patent claims licensable by a Contributor which are 29 | necessarily infringed by the use or sale of its Contribution alone or when 30 | combined with the Program. 31 | 32 | "Program" means the Contributions distributed in accordance with this 33 | Agreement. 34 | 35 | "Recipient" means anyone who receives the Program under this Agreement, 36 | including all Contributors. 37 | 38 | 2. GRANT OF RIGHTS 39 | 40 | a) Subject to the terms of this Agreement, each Contributor hereby grants 41 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 42 | reproduce, prepare derivative works of, publicly display, publicly perform, 43 | distribute and sublicense the Contribution of such Contributor, if any, and 44 | such derivative works, in source code and object code form. 45 | 46 | b) Subject to the terms of this Agreement, each Contributor hereby grants 47 | Recipient a non-exclusive, worldwide, royalty-free patent license under 48 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 49 | transfer the Contribution of such Contributor, if any, in source code and 50 | object code form. This patent license shall apply to the combination of the 51 | Contribution and the Program if, at the time the Contribution is added by the 52 | Contributor, such addition of the Contribution causes such combination to be 53 | covered by the Licensed Patents. The patent license shall not apply to any 54 | other combinations which include the Contribution. No hardware per se is 55 | licensed hereunder. 56 | 57 | c) Recipient understands that although each Contributor grants the licenses 58 | to its Contributions set forth herein, no assurances are provided by any 59 | Contributor that the Program does not infringe the patent or other 60 | intellectual property rights of any other entity. Each Contributor disclaims 61 | any liability to Recipient for claims brought by any other entity based on 62 | infringement of intellectual property rights or otherwise. As a condition to 63 | exercising the rights and licenses granted hereunder, each Recipient hereby 64 | assumes sole responsibility to secure any other intellectual property rights 65 | needed, if any. For example, if a third party patent license is required to 66 | allow Recipient to distribute the Program, it is Recipient's responsibility 67 | to acquire that license before distributing the Program. 68 | 69 | d) Each Contributor represents that to its knowledge it has sufficient 70 | copyright rights in its Contribution, if any, to grant the copyright license 71 | set forth in this Agreement. 72 | 73 | 3. REQUIREMENTS 74 | 75 | A Contributor may choose to distribute the Program in object code form under 76 | its own license agreement, provided that: 77 | 78 | a) it complies with the terms and conditions of this Agreement; and 79 | 80 | b) its license agreement: 81 | 82 | i) effectively disclaims on behalf of all Contributors all warranties and 83 | conditions, express and implied, including warranties or conditions of title 84 | and non-infringement, and implied warranties or conditions of merchantability 85 | and fitness for a particular purpose; 86 | 87 | ii) effectively excludes on behalf of all Contributors all liability for 88 | damages, including direct, indirect, special, incidental and consequential 89 | damages, such as lost profits; 90 | 91 | iii) states that any provisions which differ from this Agreement are offered 92 | by that Contributor alone and not by any other party; and 93 | 94 | iv) states that source code for the Program is available from such 95 | Contributor, and informs licensees how to obtain it in a reasonable manner on 96 | or through a medium customarily used for software exchange. 97 | 98 | When the Program is made available in source code form: 99 | 100 | a) it must be made available under this Agreement; and 101 | 102 | b) a copy of this Agreement must be included with each copy of the Program. 103 | 104 | Contributors may not remove or alter any copyright notices contained within 105 | the Program. 106 | 107 | Each Contributor must identify itself as the originator of its Contribution, 108 | if any, in a manner that reasonably allows subsequent Recipients to identify 109 | the originator of the Contribution. 110 | 111 | 4. COMMERCIAL DISTRIBUTION 112 | 113 | Commercial distributors of software may accept certain responsibilities with 114 | respect to end users, business partners and the like. While this license is 115 | intended to facilitate the commercial use of the Program, the Contributor who 116 | includes the Program in a commercial product offering should do so in a 117 | manner which does not create potential liability for other Contributors. 118 | Therefore, if a Contributor includes the Program in a commercial product 119 | offering, such Contributor ("Commercial Contributor") hereby agrees to defend 120 | and indemnify every other Contributor ("Indemnified Contributor") against any 121 | losses, damages and costs (collectively "Losses") arising from claims, 122 | lawsuits and other legal actions brought by a third party against the 123 | Indemnified Contributor to the extent caused by the acts or omissions of such 124 | Commercial Contributor in connection with its distribution of the Program in 125 | a commercial product offering. The obligations in this section do not apply 126 | to any claims or Losses relating to any actual or alleged intellectual 127 | property infringement. In order to qualify, an Indemnified Contributor must: 128 | a) promptly notify the Commercial Contributor in writing of such claim, and 129 | b) allow the Commercial Contributor tocontrol, and cooperate with the 130 | Commercial Contributor in, the defense and any related settlement 131 | negotiations. The Indemnified Contributor may participate in any such claim 132 | at its own expense. 133 | 134 | For example, a Contributor might include the Program in a commercial product 135 | offering, Product X. That Contributor is then a Commercial Contributor. If 136 | that Commercial Contributor then makes performance claims, or offers 137 | warranties related to Product X, those performance claims and warranties are 138 | such Commercial Contributor's responsibility alone. Under this section, the 139 | Commercial Contributor would have to defend claims against the other 140 | Contributors related to those performance claims and warranties, and if a 141 | court requires any other Contributor to pay any damages as a result, the 142 | Commercial Contributor must pay those damages. 143 | 144 | 5. NO WARRANTY 145 | 146 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON 147 | AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER 148 | EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR 149 | CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A 150 | PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the 151 | appropriateness of using and distributing the Program and assumes all risks 152 | associated with its exercise of rights under this Agreement , including but 153 | not limited to the risks and costs of program errors, compliance with 154 | applicable laws, damage to or loss of data, programs or equipment, and 155 | unavailability or interruption of operations. 156 | 157 | 6. DISCLAIMER OF LIABILITY 158 | 159 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 160 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 161 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 162 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 163 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 164 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 165 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 166 | OF SUCH DAMAGES. 167 | 168 | 7. GENERAL 169 | 170 | If any provision of this Agreement is invalid or unenforceable under 171 | applicable law, it shall not affect the validity or enforceability of the 172 | remainder of the terms of this Agreement, and without further action by the 173 | parties hereto, such provision shall be reformed to the minimum extent 174 | necessary to make such provision valid and enforceable. 175 | 176 | If Recipient institutes patent litigation against any entity (including a 177 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 178 | (excluding combinations of the Program with other software or hardware) 179 | infringes such Recipient's patent(s), then such Recipient's rights granted 180 | under Section 2(b) shall terminate as of the date such litigation is filed. 181 | 182 | All Recipient's rights under this Agreement shall terminate if it fails to 183 | comply with any of the material terms or conditions of this Agreement and 184 | does not cure such failure in a reasonable period of time after becoming 185 | aware of such noncompliance. If all Recipient's rights under this Agreement 186 | terminate, Recipient agrees to cease use and distribution of the Program as 187 | soon as reasonably practicable. However, Recipient's obligations under this 188 | Agreement and any licenses granted by Recipient relating to the Program shall 189 | continue and survive. 190 | 191 | Everyone is permitted to copy and distribute copies of this Agreement, but in 192 | order to avoid inconsistency the Agreement is copyrighted and may only be 193 | modified in the following manner. The Agreement Steward reserves the right to 194 | publish new versions (including revisions) of this Agreement from time to 195 | time. No one other than the Agreement Steward has the right to modify this 196 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 197 | Eclipse Foundation may assign the responsibility to serve as the Agreement 198 | Steward to a suitable separate entity. Each new version of the Agreement will 199 | be given a distinguishing version number. The Program (including 200 | Contributions) may always be distributed subject to the version of the 201 | Agreement under which it was received. In addition, after a new version of 202 | the Agreement is published, Contributor may elect to distribute the Program 203 | (including its Contributions) under the new version. Except as expressly 204 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 205 | licenses to the intellectual property of any Contributor under this 206 | Agreement, whether expressly, by implication, estoppel or otherwise. All 207 | rights in the Program not expressly granted under this Agreement are 208 | reserved. 209 | 210 | This Agreement is governed by the laws of the State of New York and the 211 | intellectual property laws of the United States of America. No party to this 212 | Agreement will bring a legal action under this Agreement more than one year 213 | after the cause of action arose. Each party waives its rights to a jury trial 214 | in any resulting litigation. 215 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learning Clojure 2 | 3 | This is my personal Clojure learning project. 4 | 5 | ## Clojure Documentation and References 6 | 7 | * [Clojure Home Page](http://clojure.org/) 8 | * [Clojure Reference](http://clojure.org/reference/reader) 9 | * [Clojure API Documentation](http://clojure.org/api/api) 10 | * [Clojure Cheatsheet](http://clojure.org/api/cheatsheet) 11 | * [ClojureScript Cheatsheet](http://cljs.info/cheatsheet/) 12 | * [Clojure API Reference](https://clojure.github.io/clojure/index.html) 13 | * [Clojure Quick Reference](https://clojuredocs.org/quickref) 14 | * [Clojure Style Guide](https://github.com/bbatsov/clojure-style-guide) 15 | 16 | ## Clojure Online REPLs 17 | 18 | * [Clojure Online REPL](https://repl.it/) 19 | * [ClojureScript Online REPL](https://clojurescript.io) 20 | * [Gorilla REPL](http://gorilla-repl.org) 21 | 22 | ## Clojure Libraries and OpenSource 23 | 24 | * [Clojars Community Repository](https://clojars.org/) 25 | * [Clojure at Github](https://github.com/clojure) 26 | * See also [Clojure Toolbox](http://www.clojure-toolbox.com/) 27 | 28 | ## Clojure Web Frameworks 29 | 30 | * [Luminus](http://www.luminusweb.net/) 31 | * [Pedestal](http://pedestal.io/pedestal/0.7/index.html) 32 | * [Hoplon](http://hoplon.io/) 33 | * [Compojure](https://github.com/weavejester/compojure/wiki) 34 | * [Ring](https://github.com/ring-clojure/ring) 35 | * [Reitit](https://github.com/metosin/reitit) 36 | * [Om](https://github.com/omcljs/om) 37 | * [clj-http](https://github.com/dakrone/clj-http) 38 | 39 | Some template engines: 40 | 41 | * [Selmer](https://github.com/yogthos/Selmer) 42 | * [Hiccup](https://github.com/weavejester/hiccup) 43 | 44 | 45 | ## Build Tools 46 | 47 | * [Leiningen](http://leiningen.org/) and a number of [plugins](https://github.com/technomancy/leiningen/wiki/Plugins) 48 | * [Boot](https://github.com/boot-clj/boot) 49 | 50 | ## Clojure Editors 51 | 52 | * [Clojure Sublimed](https://github.com/tonsky/Clojure-Sublimed), consider [this](https://tonsky.me/blog/sublime-clojure/) 53 | * [Sublime Clojure](https://github.com/jasongilman/SublimeClojureSetup) 54 | * [Sublime Tutkain](https://tutkain.flowthing.me) 55 | * [Emacs](http://aquamacs.org/) with a [number of plugins](https://github.com/clojure-emacs). 56 | * [Light Table Editor](http://lighttable.com/) 57 | * [Cursive IntelliJ Plugin](https://cursive-ide.com/) 58 | * [Counterclockwise Eclipse Plugin](https://github.com/ccw-ide/ccw) 59 | 60 | See if your favorite has [Parinfer](https://shaunlebron.github.io/parinfer/) support, which makes writing Clojure code so much easier and enjoyable. 61 | 62 | ## Clojure Books 63 | 64 | **From O'Reilly** 65 | 66 | * [Clojure for the Brave and True](http://shop.oreilly.com/product/9781593275914.do) (free to [read online](http://www.braveclojure.com/)) 67 | * [Living Clojure](http://shop.oreilly.com/product/0636920034292.do) 68 | * [Clojure Cookbook](http://shop.oreilly.com/product/0636920029786.do) 69 | * [Clojure Programming](http://shop.oreilly.com/product/0636920013754.do) 70 | 71 | **From Manning** 72 | 73 | * [The Joy of Clojure](https://www.manning.com/books/the-joy-of-clojure-second-edition) 74 | * [Clojure in Action](https://www.manning.com/books/clojure-in-action-second-edition) 75 | * [Clojure: The Essential Reference](https://www.manning.com/books/clojure-the-essential-reference) 76 | 77 | **From APress** 78 | 79 | * [Practical Clojure](http://www.apress.com/la/book/9781430272311) 80 | * [Quick Clojure](https://www.apress.com/la/book/9781484229514) 81 | * [Reactive with ClojureScript Recipes](https://www.apress.com/la/book/9781484230084) 82 | 83 | **From The Pragmatic Bookshelf** 84 | 85 | * [Clojure Applied](https://pragprog.com/book/vmclojeco/clojure-applied) 86 | * [Mastering Clojure Macros](https://pragprog.com/book/cjclojure/mastering-clojure-macros) 87 | * [Programming Clojure](https://pragprog.com/titles/shcloj3/programming-clojure-third-edition/) 88 | * [Web Development with Clojure](https://pragprog.com/titles/dswdcloj3/web-development-with-clojure-third-edition/) 89 | * [Functional Programming: A PragPub Anthology](https://pragprog.com/titles/ppanth/functional-programming-a-pragpub-anthology/) 90 | 91 | **From PackPub** 92 | 93 | * [Clojure High Performance Programming](https://www.packtpub.com/application-development/clojure-high-performance-programming) 94 | * [Clojure Reactive Programming](https://www.packtpub.com/web-development/clojure-reactive-programming) 95 | * [Clojure for Domain Specific Languages](https://www.packtpub.com/application-development/clojure-domain-specific-languages) 96 | * [Clojure Data Structures and Algorithms Cookbook](https://www.packtpub.com/application-development/clojure-data-structures-and-algorithms-cookbook) 97 | * [Clojure Web Development Essentials](https://www.packtpub.com/application-development/clojure-web-development-essentials) 98 | * [Learning ClojureScript](https://www.packtpub.com/web-development/learning-clojurescript) 99 | * [Mastering Clojure](https://www.packtpub.com/application-development/mastering-clojure) 100 | * And [many more...](https://www.packtpub.com/all/?search=clojure&offset=&rows=48&sort=) 101 | 102 | **From No Starch Press** 103 | 104 | * [Clojure for the Brave and True](https://www.nostarch.com/clojure) 105 | 106 | **From Lean Pub** 107 | 108 | * [Programming in Clojure](https://leanpub.com/programming-clojure) 109 | * [ClojureScript Unraveled](https://leanpub.com/clojurescript-unraveled) 110 | * [Elements of Clojure](https://leanpub.com/elementsofclojure) 111 | * [Clojure Extended: Java interop](https://leanpub.com/clojure-java-interop) 112 | * [Clojure Polymorphism](https://leanpub.com/clojurepolymorphism) 113 | * [Building a System in Clojure (and ClojureScript)](https://leanpub.com/building-a-system-in-clojure) 114 | 115 | ## Online Training 116 | 117 | **From PluralSight** 118 | 119 | * [Clojure Fundamentals](https://www.pluralsight.com/courses/clojure-fundamentals-part-one) 120 | * [Functional Programming with Clojure](https://www.pluralsight.com/courses/functional-programming-clojure) 121 | * [Clojure Concurrency](https://www.pluralsight.com/courses/clojure-concurrency-tutorial) 122 | 123 | **From Safari/O'Reilly** 124 | 125 | * [Learning Clojure](http://my.safaribooksonline.com/video/programming/clojure/9781771373623#) 126 | * [Building Microservices with Clojure](http://my.safaribooksonline.com/video/programming/clojure/9781771374354) 127 | * [Building Web Applications with Clojure](http://my.safaribooksonline.com/video/programming/clojure/9781783286157) 128 | * [Building Web Applications in Clojure](http://my.safaribooksonline.com/video/programming/clojure/9781491917206) 129 | * [Clojure Inside Out](http://my.safaribooksonline.com/video/programming/clojure/9781449368647) 130 | * [Learning ClojureScript](http://my.safaribooksonline.com/video/programming/clojure/9781771373890) 131 | * [Communicating Sequential Processes with core.async](http://my.safaribooksonline.com/video/programming/clojure/9781771374293) 132 | * [Functional Thinking](http://my.safaribooksonline.com/video/programming/9781449368630) 133 | 134 | ## Blogs and Interesting Articles 135 | 136 | * [Planet Clojure Blog](http://planet.clojure.in/) 137 | * [Disclojure Blog](http://disclojure.org/) 138 | * [An In-Depth Look at Clojure Collections](https://www.infoq.com/articles/in-depth-look-clojure-collections) 139 | * [Clojure Design Patterns](http://mishadoff.com/blog/clojure-design-patterns/) 140 | 141 | ## Interesting Videos 142 | 143 | **ClojureTV** 144 | 145 | * [Clojure at Scale @WalmartLabs](https://www.youtube.com/watch?v=av9Xi6CNqq4) 146 | * [Components Just Enough Structure by Stuart Sierra](https://www.youtube.com/watch?v=13cmHf_kt-Q) 147 | * [ClojureScript for Skeptics](https://www.youtube.com/watch?v=gsffg5xxFQI) 148 | * [Debugging Clojure with Cursive](https://www.youtube.com/watch?v=av9Xi6CNqq4) 149 | * [Clojure Made Simple](https://www.youtube.com/watch?v=VSdnJDO-xdg) 150 | * [One Ring to Bind Them](https://www.youtube.com/watch?v=qqNevHwH47w) 151 | * [Rich Hickey Unveils ClojureScript](https://www.youtube.com/watch?v=tVooR-dF_Ag) 152 | 153 | **InfoQ** 154 | 155 | * [RESTful Clojure](https://www.infoq.com/presentations/RESTful-Clojure) 156 | * [Clojure and the Web](https://www.infoq.com/presentations/Clojure-and-the-Web) 157 | * [What Sucks about Clojure...and why you'll love it anyway](https://www.infoq.com/presentations/What-Sucks-about-Clojure-and-Why-You-ll-Love-It-Anyway) 158 | * [Clojure after the Honeymoon](https://www.infoq.com/presentations/Clojure-Java-Story) 159 | * [Down the Clojure Rabbit Hole](https://www.infoq.com/presentations/clojure-stories?utm_campaign=infoq_content&utm_source=infoq&utm_medium=feed&utm_term=global) 160 | * [An Introduction to Clojure and ClojureScript](https://www.infoq.com/presentations/clojure-clojurescript-libraries?utm_campaign=infoq_content&utm_source=infoq&utm_medium=feed&utm_term=global) 161 | * [Relevance of ClojureScript](https://www.infoq.com/presentations/clojurescript-es6?utm_campaign=infoq_content&utm_source=infoq&utm_medium=feed&utm_term=global) 162 | * [Why Prismatic Goes Faster with Clojure](https://www.infoq.com/presentations/Why-Prismatic-Goes-Faster-With-Clojure) 163 | * [Clojure core.async](https://www.infoq.com/presentations/clojure-core-async) 164 | * [Concurrency in Clojure](https://www.infoq.com/presentations/Concurrency-Clojure) 165 | * [Clojure Solution to the Expression Problem](https://www.infoq.com/presentations/Clojure-Expression-Problem) 166 | * [Clojure: The Art of Abstraction](https://www.infoq.com/presentations/Clojure-The-Art-of-Abstraction) 167 | * [Namespaces, Vars and Symbols (Oh, My!)](https://www.infoq.com/presentations/Clojure-Namespaces-Vars-Symbols) 168 | * [Clojure in the Field](https://www.infoq.com/presentations/Clojure-tips) 169 | * [Continuous Testing in Clojure](https://www.infoq.com/presentations/Continuous-Testing-Clojure) 170 | * [Leiningen 2 - Humane build management for Clojure](https://www.infoq.com/presentations/Leiningen-2-Clojure) 171 | * [Macros: Why, When and How?](https://www.infoq.com/presentations/macros-clojure-west-2013) 172 | * [Persistent Data Structures and Managed References by Rich Hickey](https://www.infoq.com/presentations/Value-Identity-State-Rich-Hickey) 173 | 174 | **Channel 9** 175 | 176 | * [Expert to Expert: Rich Hickey and Brian Beckman - Insider Clojure](https://channel9.msdn.com/shows/Going+Deep/Expert-to-Expert-Rich-Hickey-and-Brian-Beckman-Inside-Clojure/) 177 | 178 | ## Clojure Adoption Stories 179 | 180 | * [Clojure at Scale by Walmart](http://blog.cognitect.com/blog/2015/6/30/walmart-runs-clojure-at-scale) 181 | * [60,000% Growth Using Clojure and AWS by Room Key](http://www.colinsteele.org/post/27929539434/60000-growth-in-7-months-using-clojure-and-aws) 182 | * [ClojureScript Integration Roadmap by Greenius](http://about.greeni.us/greenius-clojurescript-integration-roadmap/) 183 | * [A New Era of Application Services at Puppet Labs](https://puppet.com/blog/a-new-era-of-application-services-at-puppet-labs) 184 | * [For Clojure Nerds: Puppet Labs Application Services](https://puppet.com/blog/for-clojure-nerds-puppet-labs-application-services) 185 | * [Beanstalk + Clojure = Love (and 20x better performance)](http://blog.beanstalkapp.com/post/23998022427/beanstalk-clojure-love-and-20x-better) 186 | * [Clojure at a Newspaper](http://www.pitheringabout.com/?p=1018) 187 | * [Lessons Learned from Adopting Clojure](https://yow.eventer.com/yow-2013-1080/lessons-learned-from-adopting-clojure-by-jey-fields-1397) 188 | * [Unlocking Data-Driven Systems by Consumer Reports](https://www.youtube.com/watch?v=BNkYYYyfF48) 189 | 190 | ## Web Sites with Exercises 191 | 192 | * [Exercism](https://exercism.org/tracks/clojure) 193 | * [ClojureKoans](https://github.com/functional-koans/clojure-koans) 194 | * [ClojureScript Koans](http://clojurescriptkoans.com/) 195 | * [HackerRank](https://www.hackerrank.com/) 196 | * [Code Wars](https://www.codewars.com/dashboard) 197 | 198 | ## Mobile Apps 199 | 200 | * [Textastic](https://www.textasticapp.com) which I use to program Clojure in my iPad 201 | * [My List](https://apps.apple.com/us/app/my-lisp/id1245341806) an iOS editor with Clojure support. 202 | * [Replete](https://apps.apple.com/us/app/replete-repl/id1013465639) a iOS ClojureScript REPL. 203 | --------------------------------------------------------------------------------