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
|
||||
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.
|
||||
|
||||
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."
|
||||
:dependencies [[org.clojure/clojure "1.10.0"]
|
||||
[koan-engine "0.2.5"]]
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@
|
|||
nil
|
||||
\C
|
||||
inc
|
||||
:park "AT&T Park"
|
||||
:park "Oracle Park"
|
||||
'Giants
|
||||
"Giants"]}]
|
||||
|
||||
|
|
@ -266,4 +266,23 @@
|
|||
10
|
||||
'(+ 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"
|
||||
(= 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"))
|
||||
|
||||
"But when something doesn't exist, nothing is found"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
"Remember that a set is a *mathematical* set"
|
||||
(= __ (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}))
|
||||
|
||||
"And also the intersection"
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
(for [x __ :when (odd? x)]
|
||||
x))
|
||||
|
||||
"Combinations of these transformations is trivial"
|
||||
"Combinations of these transformations are trivial"
|
||||
(= '(1 9 25 49 81)
|
||||
(map (fn [x] (* x x))
|
||||
(filter odd? (range 10)))
|
||||
|
|
|
|||
|
|
@ -35,10 +35,10 @@
|
|||
"Yet it becomes more difficult the more steps you take"
|
||||
(= '(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))
|
||||
|
||||
"They may require other simple steps."
|
||||
"They may require other simple steps"
|
||||
(= 2 (factorial 2))
|
||||
|
||||
"Sometimes a slightly bigger step is necessary"
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
(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"
|
||||
(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"
|
||||
(= '((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)))
|
||||
|
||||
"... 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))))
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
[odds evens]))
|
||||
|
||||
(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"]))
|
||||
|
||||
"You can simulate filter + remove in one pass"
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
@(:world-series-titles (meta giants))))
|
||||
|
||||
"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
|
||||
assoc __ __)))
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
"You can do better than that - hand crafting FTW!"
|
||||
(= '(* 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)))))
|
||||
|
||||
"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