Compare commits
13 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d2b6ecc98 | ||
|
|
76b279a8a8 | ||
|
|
3ddfa8c241 | ||
|
|
9ed29b7922 | ||
|
|
a9c22921a5 | ||
|
|
d749795c31 | ||
|
|
040070bbed | ||
|
|
eb73f39c9e | ||
|
|
9c115996f9 | ||
|
|
3afe01adc7 | ||
|
|
ba141d0fc2 | ||
|
|
9481906390 | ||
|
|
3cc7b91c23 |
15 changed files with 179 additions and 20 deletions
|
|
@ -152,7 +152,7 @@ to add to existing koans. So write some fun exercises, add your answers to
|
||||||
|
|
||||||
Please follow the guidelines in
|
Please follow the guidelines in
|
||||||
http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html for
|
http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html for
|
||||||
commmit messages, and put your code in a feature branch (not master) before
|
commit messages, and put your code in a feature branch (not master) before
|
||||||
making the pull request. This makes patches easier to review.
|
making the pull request. This makes patches easier to review.
|
||||||
|
|
||||||
Feel free to contact me (Colin Jones / trptcolin) on Github or elsewhere if you
|
Feel free to contact me (Colin Jones / trptcolin) on Github or elsewhere if you
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
(defproject clojure-koans "0.5.1"
|
(defproject clojure-koans "0.5.2-SNAPSHOT"
|
||||||
:description "The Clojure koans."
|
:description "The Clojure koans."
|
||||||
:dependencies [[org.clojure/clojure "1.10.0"]
|
:dependencies [[org.clojure/clojure "1.10.0"]
|
||||||
[koan-engine "0.2.5"]]
|
[koan-engine "0.2.5"]]
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,7 @@
|
||||||
nil
|
nil
|
||||||
\C
|
\C
|
||||||
inc
|
inc
|
||||||
:park "AT&T Park"
|
:park "Oracle Park"
|
||||||
'Giants
|
'Giants
|
||||||
"Giants"]}]
|
"Giants"]}]
|
||||||
|
|
||||||
|
|
@ -266,4 +266,23 @@
|
||||||
10
|
10
|
||||||
'(+ 9 1)]}]
|
'(+ 9 1)]}]
|
||||||
|
|
||||||
|
["25_threading_macros" {"__" [{:a 1}
|
||||||
|
"Hello world, and moon, and stars"
|
||||||
|
"String with a trailing space"
|
||||||
|
6
|
||||||
|
1
|
||||||
|
[2 3 4]
|
||||||
|
12
|
||||||
|
[1 2 3]]}]
|
||||||
|
|
||||||
|
["26_transducers" {"__" ['(2 3 4)
|
||||||
|
[2 4]
|
||||||
|
[2 4]
|
||||||
|
[2 4]
|
||||||
|
6]}]
|
||||||
|
|
||||||
|
["27_multimethods" {"__" ["Hello, World!"
|
||||||
|
"Hello there"
|
||||||
|
1
|
||||||
|
6]}]
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@
|
||||||
"Maybe you want to find the index of the first occurrence of a substring"
|
"Maybe you want to find the index of the first occurrence of a substring"
|
||||||
(= 0 (string/index-of "hello world" __))
|
(= 0 (string/index-of "hello world" __))
|
||||||
|
|
||||||
"Or maybe the last index of the same"
|
"Or maybe the last index of the same substring"
|
||||||
(= __ (string/last-index-of "hello world, hello" "hello"))
|
(= __ (string/last-index-of "hello world, hello" "hello"))
|
||||||
|
|
||||||
"But when something doesn't exist, nothing is found"
|
"But when something doesn't exist, nothing is found"
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
"Remember that a set is a *mathematical* set"
|
"Remember that a set is a *mathematical* set"
|
||||||
(= __ (set '(1 1 2 2 3 3 4 4 5 5)))
|
(= __ (set '(1 1 2 2 3 3 4 4 5 5)))
|
||||||
|
|
||||||
"You can ask clojure for the union of two sets"
|
"You can ask Clojure for the union of two sets"
|
||||||
(= __ (set/union #{1 2 3 4} #{2 3 5}))
|
(= __ (set/union #{1 2 3 4} #{2 3 5}))
|
||||||
|
|
||||||
"And also the intersection"
|
"And also the intersection"
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
(for [x __ :when (odd? x)]
|
(for [x __ :when (odd? x)]
|
||||||
x))
|
x))
|
||||||
|
|
||||||
"Combinations of these transformations is trivial"
|
"Combinations of these transformations are trivial"
|
||||||
(= '(1 9 25 49 81)
|
(= '(1 9 25 49 81)
|
||||||
(map (fn [x] (* x x))
|
(map (fn [x] (* x x))
|
||||||
(filter odd? (range 10)))
|
(filter odd? (range 10)))
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,10 @@
|
||||||
"Yet it becomes more difficult the more steps you take"
|
"Yet it becomes more difficult the more steps you take"
|
||||||
(= '(6 5 4 3 2) (recursive-reverse [2 3 4 5 6]))
|
(= '(6 5 4 3 2) (recursive-reverse [2 3 4 5 6]))
|
||||||
|
|
||||||
"Simple things may appear simple."
|
"Simple things may appear simple"
|
||||||
(= 1 (factorial 1))
|
(= 1 (factorial 1))
|
||||||
|
|
||||||
"They may require other simple steps."
|
"They may require other simple steps"
|
||||||
(= 2 (factorial 2))
|
(= 2 (factorial 2))
|
||||||
|
|
||||||
"Sometimes a slightly bigger step is necessary"
|
"Sometimes a slightly bigger step is necessary"
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
(let [[first-name last-name :as full-name] ["Stephen" "Hawking"]]
|
(let [[first-name last-name :as full-name] ["Stephen" "Hawking"]]
|
||||||
__))
|
__))
|
||||||
|
|
||||||
"Break up maps by key"
|
"Break up maps by keys"
|
||||||
(= "123 Test Lane, Testerville, TX"
|
(= "123 Test Lane, Testerville, TX"
|
||||||
(let [{street-address :street-address, city :city, state :state} test-address]
|
(let [{street-address :street-address, city :city, state :state} test-address]
|
||||||
__))
|
__))
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
"If you need to, you can start each sequence with an offset"
|
"If you need to, you can start each sequence with an offset"
|
||||||
(= '((0 1 2) (5 6 7) (10 11 12)) (partition 3 __ (range 13)))
|
(= '((0 1 2) (5 6 7) (10 11 12)) (partition 3 __ (range 13)))
|
||||||
|
|
||||||
"Consider padding the last sequence with some default values..."
|
"Consider padding the last sequence with some default values"
|
||||||
(= '((0 1 2) (3 4 5) (6 :hello)) (partition 3 3 [__] (range 7)))
|
(= '((0 1 2) (3 4 5) (6 :hello)) (partition 3 3 [__] (range 7)))
|
||||||
|
|
||||||
"... but notice that they will only pad up to the given sequence length"
|
"But notice that they will only pad up to the given sequence length"
|
||||||
(= '((0 1 2) (3 4 5) __) (partition 3 3 [:these :are "my" "words"] (range 7))))
|
(= '((0 1 2) (3 4 5) __) (partition 3 3 [:these :are "my" "words"] (range 7))))
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
[odds evens]))
|
[odds evens]))
|
||||||
|
|
||||||
(meditations
|
(meditations
|
||||||
"To categorize a collection by some function, use group-by."
|
"To categorize a collection by some function, use group-by"
|
||||||
(= __ (group-by count ["hello" "world" "foo" "bar"]))
|
(= __ (group-by count ["hello" "world" "foo" "bar"]))
|
||||||
|
|
||||||
"You can simulate filter + remove in one pass"
|
"You can simulate filter + remove in one pass"
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@
|
||||||
@(:world-series-titles (meta giants))))
|
@(:world-series-titles (meta giants))))
|
||||||
|
|
||||||
"You can also create a new object from another object with metadata"
|
"You can also create a new object from another object with metadata"
|
||||||
(= {:league "National League" :park "AT&T Park"}
|
(= {:league "National League" :park "Oracle Park"}
|
||||||
(meta (vary-meta giants
|
(meta (vary-meta giants
|
||||||
assoc __ __)))
|
assoc __ __)))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@
|
||||||
"You can do better than that - hand crafting FTW!"
|
"You can do better than that - hand crafting FTW!"
|
||||||
(= '(* 10 2) (macroexpand '(infix-concise (10 * 2))))
|
(= '(* 10 2) (macroexpand '(infix-concise (10 * 2))))
|
||||||
|
|
||||||
"Things don't always work as you would like them to... "
|
"Things don't always work as you would like them to"
|
||||||
(= '(+ 10 (2 * 3)) (macroexpand '(infix-concise (10 + (2 * 3)))))
|
(= '(+ 10 (2 * 3)) (macroexpand '(infix-concise (10 + (2 * 3)))))
|
||||||
|
|
||||||
"Really, you don't understand recursion until you understand recursion"
|
"Really, you don't understand recursion until you understand recursion"
|
||||||
|
|
|
||||||
66
src/koans/25_threading_macros.clj
Normal file
66
src/koans/25_threading_macros.clj
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
(ns koans.25-threading-macros
|
||||||
|
(:require [koan-engine.core :refer :all]))
|
||||||
|
|
||||||
|
(def a-list
|
||||||
|
'(1 2 3 4 5))
|
||||||
|
|
||||||
|
(def a-list-with-maps
|
||||||
|
'({:a 1} {:a 2} {:a 3}))
|
||||||
|
|
||||||
|
(defn function-that-takes-a-map [map a b]
|
||||||
|
(get map :a))
|
||||||
|
|
||||||
|
(defn function-that-takes-a-coll [a b coll]
|
||||||
|
(map :a coll))
|
||||||
|
|
||||||
|
(meditations
|
||||||
|
"We can use thread first for more readable sequential operations"
|
||||||
|
(= __
|
||||||
|
(-> {}
|
||||||
|
(assoc :a 1)))
|
||||||
|
|
||||||
|
"Consider also the case of strings"
|
||||||
|
(= __
|
||||||
|
(-> "Hello world"
|
||||||
|
(str ", and moon")
|
||||||
|
(str ", and stars")))
|
||||||
|
|
||||||
|
"When a function has no arguments to partially apply, just reference it"
|
||||||
|
(= __
|
||||||
|
(-> "String with a trailing space "
|
||||||
|
clojure.string/trim))
|
||||||
|
|
||||||
|
"Most operations that take a scalar value as an argument can be threaded-first"
|
||||||
|
(= __
|
||||||
|
(-> {}
|
||||||
|
(assoc :a 1)
|
||||||
|
(assoc :b 2)
|
||||||
|
(assoc :c {:d 4
|
||||||
|
:e 5})
|
||||||
|
(update-in [:c :e] inc)
|
||||||
|
(get-in [:c :e])))
|
||||||
|
|
||||||
|
"We can use functions we have written ourselves that follow this pattern"
|
||||||
|
(= __
|
||||||
|
(-> {}
|
||||||
|
(assoc :a 1)
|
||||||
|
(function-that-takes-a-map "hello" "there")))
|
||||||
|
|
||||||
|
"We can also thread last using ->>"
|
||||||
|
(= __
|
||||||
|
(->> [1 2 3]
|
||||||
|
(map inc)))
|
||||||
|
|
||||||
|
"Most operations that take a collection can be threaded-last"
|
||||||
|
(= __
|
||||||
|
(->> a-list
|
||||||
|
(map inc)
|
||||||
|
(filter even?)
|
||||||
|
(into [])
|
||||||
|
(reduce +)))
|
||||||
|
|
||||||
|
"We can use functions we have written ourselves that follow this pattern"
|
||||||
|
(= __
|
||||||
|
(->> a-list-with-maps
|
||||||
|
(function-that-takes-a-coll "hello" "there")
|
||||||
|
(into []))))
|
||||||
30
src/koans/26_transducers.clj
Normal file
30
src/koans/26_transducers.clj
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
(ns koans.26-transducers
|
||||||
|
(:require [koan-engine.core :refer :all]))
|
||||||
|
|
||||||
|
(def example-transducer
|
||||||
|
(map inc))
|
||||||
|
|
||||||
|
(def transforms
|
||||||
|
(comp (map inc)
|
||||||
|
(filter even?)))
|
||||||
|
|
||||||
|
(meditations
|
||||||
|
"A sequence operation with only one argument often returns a transducer"
|
||||||
|
(= __
|
||||||
|
(sequence example-transducer [1 2 3]))
|
||||||
|
|
||||||
|
"Consider that sequence operations can be composed as transducers"
|
||||||
|
(= __
|
||||||
|
(transduce transforms conj [1 2 3]))
|
||||||
|
|
||||||
|
"We can do this eagerly"
|
||||||
|
(= __
|
||||||
|
(into [] transforms [1 2 3]))
|
||||||
|
|
||||||
|
"Or lazily"
|
||||||
|
(= __
|
||||||
|
(sequence transforms [1 2 3]))
|
||||||
|
|
||||||
|
"The transduce function can combine mapping and reduction"
|
||||||
|
(= __
|
||||||
|
(transduce transforms + [1 2 3])))
|
||||||
44
src/koans/27_multimethods.clj
Normal file
44
src/koans/27_multimethods.clj
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
(ns koans.27-multimethods
|
||||||
|
(:require [koan-engine.core :refer :all]))
|
||||||
|
|
||||||
|
(defmulti multimethod-without-args
|
||||||
|
(fn [keyword-arg] keyword-arg))
|
||||||
|
|
||||||
|
(defmethod multimethod-without-args :first [_]
|
||||||
|
(str "Hello, World!"))
|
||||||
|
|
||||||
|
(defmethod multimethod-without-args :second [_]
|
||||||
|
(str "Hello there"))
|
||||||
|
|
||||||
|
(defmulti multimethod-with-args
|
||||||
|
(fn [opt-one opt-two] opt-one))
|
||||||
|
|
||||||
|
(defmethod multimethod-with-args :path-one [_ opts]
|
||||||
|
(:first-opt opts))
|
||||||
|
|
||||||
|
(defmethod multimethod-with-args :path-two [_ opts]
|
||||||
|
(let [numbers (:second-opt opts)]
|
||||||
|
(->> numbers
|
||||||
|
(map inc)
|
||||||
|
(reduce +))))
|
||||||
|
|
||||||
|
(defmethod multimethod-with-args :path-three [_])
|
||||||
|
|
||||||
|
(meditations
|
||||||
|
"A multimethod takes one or more arguments to dispatch on"
|
||||||
|
(= __
|
||||||
|
(multimethod-without-args :first))
|
||||||
|
|
||||||
|
"Though it can be ignored and represented by _ in defmethods"
|
||||||
|
(= __
|
||||||
|
(multimethod-without-args :second))
|
||||||
|
|
||||||
|
"Alternatively, we can use the arguments in defmethods"
|
||||||
|
(= __
|
||||||
|
(multimethod-with-args :path-one {:first-opt 1
|
||||||
|
:second-opt 2}))
|
||||||
|
|
||||||
|
"This allows us to do something different in each method implementation"
|
||||||
|
(= __
|
||||||
|
(multimethod-with-args :path-two {:first-opt 1
|
||||||
|
:second-opt [0 1 2]})))
|
||||||
Loading…
Reference in a new issue