From 3d6d81c63ab43c398d35337e3d57b233c75ad940 Mon Sep 17 00:00:00 2001 From: Manas Karekar Date: Sun, 3 Mar 2013 04:46:32 -0500 Subject: [PATCH 1/6] Simple solutions to clojure koans --- src/koans/01_equalities.clj | 14 +++++------ src/koans/02_lists.clj | 20 ++++++++-------- src/koans/03_vectors.clj | 22 ++++++++--------- src/koans/04_sets.clj | 12 +++++----- src/koans/05_maps.clj | 32 ++++++++++++------------- src/koans/06_functions.clj | 16 ++++++------- src/koans/07_conditionals.clj | 20 ++++++++-------- src/koans/08_higher_order_functions.clj | 20 ++++++++-------- 8 files changed, 78 insertions(+), 78 deletions(-) diff --git a/src/koans/01_equalities.clj b/src/koans/01_equalities.clj index 0d1a61d..f3661ab 100644 --- a/src/koans/01_equalities.clj +++ b/src/koans/01_equalities.clj @@ -1,21 +1,21 @@ (meditations "We shall contemplate truth by testing reality, via equality" - (= __ true) + (= true true) "To understand reality, we must compare our expectations against reality" - (= __ (+ 1 1)) + (= 2 (+ 1 1)) "You can test equality of many things" - (= (+ 3 4) __ (+ 2 __)) + (= (+ 3 4) 7 (+ 2 5)) "Some things may appear different, but be the same" - (= 2 2/1 __) + (= 2 2/1 4/2) "You cannot generally float to heavens of integers" - (= __ (= 2 2.0)) + (= false (= 2 2.0)) "But a looser equality is also possible" - (== 2.0 2 __) + (== 2.0 2 4/2) "When things cannot be equal, they must be different" - (not= :fill-in-the-blank __)) + (not= :fill-in-the-blank :not)) diff --git a/src/koans/02_lists.clj b/src/koans/02_lists.clj index 2d297d3..a2847e0 100644 --- a/src/koans/02_lists.clj +++ b/src/koans/02_lists.clj @@ -1,34 +1,34 @@ (meditations "Lists can be expressed by function or a quoted form" - (= '(__ __ __ __ __) (list 1 2 3 4 5)) + (= '(1 2 3 4 5) (list 1 2 3 4 5)) "They are Clojure seqs (sequences), so they allow access to the first" - (= __ (first '(1 2 3 4 5))) + (= 1 (first '(1 2 3 4 5))) "As well as the rest" - (= __ (rest '(1 2 3 4 5))) + (= [2 3 4 5] (rest '(1 2 3 4 5))) "The rest when nothing is left is empty" - (= __ (rest '(100))) + (= [] (rest '(100))) "And construction by adding an element to the front is simple" - (= __ (cons :a '(:b :c :d :e))) + (= '(:a :b :c :d :e) (cons :a '(:b :c :d :e))) "Conjoining an element to a list can be done in the reverse order" - (= __ (conj '(:a :b :c :d :e) 0)) + (= '(0 :a :b :c :d :e) (conj '(:a :b :c :d :e) 0)) "You can use a list like a stack to get the first element" - (= __ (peek '(:a :b :c :d :e))) + (= :a (peek '(:a :b :c :d :e))) "Or the others" - (= __ (pop '(:a :b :c :d :e))) + (= '(:b :c :d :e) (pop '(:a :b :c :d :e))) "But watch out if you try to pop nothing" - (= __ (try + (= "No dice!" (try (pop '()) (catch IllegalStateException e "No dice!"))) "The rest of nothing isn't so strict" - (= __ (try + (= () (try (rest '()) (catch IllegalStateException e "No dice!")))) diff --git a/src/koans/03_vectors.clj b/src/koans/03_vectors.clj index 9397378..a40cf73 100644 --- a/src/koans/03_vectors.clj +++ b/src/koans/03_vectors.clj @@ -1,33 +1,33 @@ (meditations "You can use vectors in clojure to create an 'Array' like structure" - (= __ (count [42])) + (= 1 (count [42])) "You can create a vector in several ways" - (= __ (vec nil)) + (= [] (vec nil)) "And populate it in either of these ways" - (= __ (vec '(1))) + (= [1] (vec '(1))) "There is another way as well" - (= __ (vector nil)) + (= [nil] (vector nil)) "But you can populate it with any number of elements at once" - (= [1 __] (vec '(1 2))) + (= [1 2] (vec '(1 2))) "And add to it as well" - (= __ (conj (vec nil) 333)) + (= [333] (conj (vec nil) 333)) "You can get the first element of a vector like so" - (= __ (first [:peanut :butter :and :jelly])) + (= :peanut (first [:peanut :butter :and :jelly])) "And the last in a similar fashion" - (= __ (last [:peanut :butter :and :jelly])) + (= :jelly (last [:peanut :butter :and :jelly])) "Or any index if you wish" - (= __ (nth [:peanut :butter :and :jelly] 3)) + (= :jelly (nth [:peanut :butter :and :jelly] 3)) "You can also slice a vector" - (= __ (subvec [:peanut :butter :and :jelly] 1 3)) + (= [:butter :and] (subvec [:peanut :butter :and :jelly] 1 3)) "Equality with collections is in terms of values" - (= (list 1 2 3) (vector 1 2 __))) + (= (list 1 2 3) (vector 1 2 3))) diff --git a/src/koans/04_sets.clj b/src/koans/04_sets.clj index d8c60a4..1d78624 100644 --- a/src/koans/04_sets.clj +++ b/src/koans/04_sets.clj @@ -1,18 +1,18 @@ (meditations "You can create a set in two ways" - (= #{} (set __)) + (= #{} (set nil)) "They are another important data structure in clojure" - (= __ (count #{1 2 3})) + (= 3 (count #{1 2 3})) "Remember that a set is a 'set'" - (= __ (set '(1 1 2 2 3 3 4 4 5 5))) + (= #{1 2 3 4 5} (set '(1 1 2 2 3 3 4 4 5 5))) "You can ask clojure for the union of two sets" - (= __ (clojure.set/union #{1 2 3 4} #{2 3 5})) + (= #{1 2 3 4 5} (clojure.set/union #{1 2 3 4} #{2 3 5})) "And also the intersection" - (= __ (clojure.set/intersection #{1 2 3 4} #{2 3 5})) + (= #{2 3} (clojure.set/intersection #{1 2 3 4} #{2 3 5})) "But don't forget about the difference" - (= __ (clojure.set/difference #{1 2 3 4 5} #{2 3 5}))) + (= #{1 4} (clojure.set/difference #{1 2 3 4 5} #{2 3 5}))) diff --git a/src/koans/05_maps.clj b/src/koans/05_maps.clj index c0cc7a6..72030bb 100644 --- a/src/koans/05_maps.clj +++ b/src/koans/05_maps.clj @@ -1,50 +1,50 @@ (meditations "There are two ways to create maps" - (= __ (hash-map)) + (= {} (hash-map)) "Maps in clojure associate keys with values" - (= __ (count (hash-map))) + (= 0 (count (hash-map))) "A value must be supplied for each key" - (= {:a 1} (hash-map :a __)) + (= {:a 1} (hash-map :a 1)) "The size is the number of entries" - (= __ (count {:a 1 :b 2})) + (= 2 (count {:a 1 :b 2})) "You can look up the value for a given key" - (= __ (get {:a 1 :b 2} :b)) + (= 2 (get {:a 1 :b 2} :b)) "Maps can be used as lookup functions" - (= __ ({:a 1 :b 2} :a)) + (= 1 ({:a 1 :b 2} :a)) "And so can keywords" - (= __ (:a {:a 1 :b 2})) + (= 1 (:a {:a 1 :b 2})) "But map keys need not be keywords" - (= __ ({2006 "Torino" 2010 "Vancouver" 2014 "Sochi"} 2010)) + (= "Vancouver" ({2006 "Torino" 2010 "Vancouver" 2014 "Sochi"} 2010)) "You may not be able to find an entry for a key" - (= __ (get {:a 1 :b 2} :c)) + (= nil (get {:a 1 :b 2} :c)) "But you can provide your own default" - (= __ (get {:a 1 :b 2} :c :key-not-found)) + (= :key-not-found (get {:a 1 :b 2} :c :key-not-found)) "You can find out if a key is present" - (= __ (contains? {:a nil :b nil} :b)) + (= true (contains? {:a nil :b nil} :b)) "Or if it is missing" - (= __ (contains? {:a nil :b nil} :c)) + (= false (contains? {:a nil :b nil} :c)) "Maps are immutable, but you can create a new, 'changed' version" - (= {1 "January" 2 __} (assoc {1 "January" } 2 "February")) + (= {1 "January" 2 "February"} (assoc {1 "January" } 2 "February")) "You can also 'remove' an entry" - (= {__ __} (dissoc {1 "January" 2 "February"} 2)) + (= {1 "January"} (dissoc {1 "January" 2 "February"} 2)) "Often you will need to get the keys (which will be in hash order)" - (= (list __ __ __) + (= (list 2006 2010 2014) (sort (keys {2006 "Torino" 2010 "Vancouver" 2014 "Sochi"}))) "Or the values" - (= (list "Sochi" "Torino" __) + (= (list "Sochi" "Torino" "Vancouver") (sort (vals {2006 "Torino" 2010 "Vancouver" 2014 "Sochi"})))) diff --git a/src/koans/06_functions.clj b/src/koans/06_functions.clj index a0742d1..5303a4e 100644 --- a/src/koans/06_functions.clj +++ b/src/koans/06_functions.clj @@ -5,25 +5,25 @@ (meditations "Functions are often defined before they are used" - (= __ (multiply-by-ten 2)) + (= 20 (multiply-by-ten 2)) "But they can also be defined inline" - (= __ ((fn [n] (* __ n)) 2)) + (= 20 ((fn [n] (* 10 n)) 2)) "Or using even shorter syntax" - (= __ (#(* 15 %) __)) + (= 20 (#(* 10 %) 2)) "Short anonymous functions may take multiple arguments" - (= __ (#(+ %1 %2 %3) 4 5 6)) + (= 15 (#(+ %1 %2 %3) 4 5 6)) "One function can beget another" - (= __ ((fn [] - ((fn [a b] (__ a b)) + (= 9 ((fn [] + ((fn [a b] (+ a b)) 4 5)))) "Higher-order functions take function arguments" - (= 25 (___ + (= 25 ((fn [func] (func 5)) (fn [n] (* n n)))) "But they are often better written using the names of functions" - (= 25 (___ square))) + (= 25 ((defn square5 [square] (square 5)) square))) diff --git a/src/koans/07_conditionals.clj b/src/koans/07_conditionals.clj index eaf5711..bde0a8c 100644 --- a/src/koans/07_conditionals.clj +++ b/src/koans/07_conditionals.clj @@ -9,38 +9,38 @@ (meditations "You will face many decisions" - (= __ (if (false? (= 4 5)) + (= :a (if (false? (= 4 5)) :a :b)) "Some of them leave you no alternative" - (= __ (if (> 4 3) + (= [] (if (> 4 3) [])) "And in such a situation you may have nothing" - (= __ (if (nil? 0) + (= nil (if (nil? 0) [:a :b :c])) "In others your alternative may be interesting" (= :glory (if (not (empty? ())) :doom - __)) + :glory)) "You may have a multitude of possible paths" (let [x 5] - (= :your-road (cond (= x __) :road-not-taken - (= x __) :another-road-not-taken - :else __))) + (= :your-road (cond (= x 2) :road-not-taken + (= x 3) :another-road-not-taken + :else :your-road))) "Or your fate may be sealed" - (= __ (if-not (zero? __) + (= 'doom (if-not (zero? 1) 'doom 'doom)) "In case of emergency, sound the alarms" (= :sirens - (explain-defcon-level __)) + (explain-defcon-level :cocked-pistol)) "But admit it when you don't know what to do" - (= __ + (= :say-what? (explain-defcon-level :yo-mama))) diff --git a/src/koans/08_higher_order_functions.clj b/src/koans/08_higher_order_functions.clj index 0d53b94..512b46d 100644 --- a/src/koans/08_higher_order_functions.clj +++ b/src/koans/08_higher_order_functions.clj @@ -1,32 +1,32 @@ (meditations "The map function relates a sequence to another" - (= [__ __ __] (map (fn [x] (* 4 x)) [1 2 3])) + (= [4 8 12] (map (fn [x] (* 4 x)) [1 2 3])) "You may create that mapping" - (= [1 4 9 16 25] (map (fn [x] __) [1 2 3 4 5])) + (= [1 4 9 16 25] (map (fn [x] (* x x)) [1 2 3 4 5])) "Or use the names of existing functions" - (= __ (map nil? [:a :b nil :c :d])) + (= [false false true false false] (map nil? [:a :b nil :c :d])) "A filter can be strong" - (= __ (filter (fn [x] false) '(:anything :goes :here))) + (= [] (filter (fn [x] false) '(:anything :goes :here))) "Or very weak" - (= __ (filter (fn [x] true) '(:anything :goes :here))) + (= [:anything :goes :here] (filter (fn [x] true) '(:anything :goes :here))) "Or somewhere in between" - (= [10 20 30] (filter (fn [x] __) [10 20 30 40 50 60 70 80])) + (= [10 20 30] (filter (fn [x] (< x 40)) [10 20 30 40 50 60 70 80])) "Maps and filters may be combined" - (= [10 20 30] (map (fn [x] __) (filter (fn [x] __) [1 2 3 4 5 6 7 8]))) + (= [10 20 30] (map (fn [x] (* 10 x)) (filter (fn [x] (< x 4)) [1 2 3 4 5 6 7 8]))) "Reducing can increase the result" - (= __ (reduce (fn [a b] (* a b)) [1 2 3 4])) + (= 24 (reduce (fn [a b] (* a b)) [1 2 3 4])) "You can start somewhere else" - (= 2400 (reduce (fn [a b] (* a b)) __ [1 2 3 4])) + (= 2400 (reduce (fn [a b] (* a b)) 100 [1 2 3 4])) "Numbers are not the only things one can reduce" (= "longest" (reduce (fn [a b] - (if (< __ __) b a)) + (if (< (count a) (count b)) b a)) ["which" "word" "is" "longest"]))) From bd5f7eadd7968eb60dcf3630bcaac5a68a7c766e Mon Sep 17 00:00:00 2001 From: Manas Karekar Date: Sun, 3 Mar 2013 16:33:39 -0500 Subject: [PATCH 2/6] Exercise 9 - runtime polymorphism --- src/koans/09_runtime_polymorphism.clj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/koans/09_runtime_polymorphism.clj b/src/koans/09_runtime_polymorphism.clj index a8171ee..37816e7 100644 --- a/src/koans/09_runtime_polymorphism.clj +++ b/src/koans/09_runtime_polymorphism.clj @@ -7,19 +7,19 @@ "!"))) (defmulti diet (fn [x] (:eater x))) -(defmethod diet :herbivore [a] __) -(defmethod diet :carnivore [a] __) -(defmethod diet :default [a] __) +(defmethod diet :herbivore [a] (str (:name a) " eats veggies.")) +(defmethod diet :carnivore [a] (str (a :name) " eats animals.")) +(defmethod diet :default [a] (str "I don't know what " (:name a) " eats.")) (meditations "Some functions can be used in different ways - with no arguments" - (= __ (hello)) + (= "Hello World!" (hello)) "With one argument" - (= __ (hello "world")) + (= "Hello, you silly world." (hello "world")) "Or with many arguments" - (= __ + (= "Hello to this group: Peter, Paul, Mary!" (hello "Peter" "Paul" "Mary")) "Multimethods allow more complex dispatching" From 2e1d4feb3c587176f3c4392f00d069564f10c105 Mon Sep 17 00:00:00 2001 From: Manas Karekar Date: Sun, 3 Mar 2013 16:35:48 -0500 Subject: [PATCH 3/6] Updated readme --- README.md | 153 +----------------------------------------------------- 1 file changed, 1 insertion(+), 152 deletions(-) diff --git a/README.md b/README.md index f3cd403..991bedd 100644 --- a/README.md +++ b/README.md @@ -1,152 +1 @@ -# Clojure Koans - -The Clojure Koans are a fun and easy way to get started with Clojure - no -experience assumed or required. Just follow the instructions below to start -making tests pass! - - -### Getting Started - -The easiest and fastest way to get the koans up and running is to [download the -latest zip file from Github](https://github.com/functional-koans/clojure-koans/downloads). -This way, you'll have all the dependencies you need, including Clojure itself -and JLine, and you can skip the rest of this section (skip to "Running the -Koans"). - -If you're starting from a cloned or forked repo, that's cool too. This way -you'll be able to track your progress in Git, and see how your answers compare -to others, by checking out the project's Network tab. You might want to create -your own branch - that way if you pull back the latest koans from master, it'll -be a bit easier to manage the inevitable conflicts if we make changes to -exercises you've already completed. - -The only things you'll need to run the Clojure Koans are: - -- JRE 1.5 or higher -- [clojure-1.5.0.jar](http://repo1.maven.org/maven2/org/clojure/clojure/1.5.0/clojure-1.5.0.zip) - -You can use [Leiningen](http://github.com/technomancy/leiningen) to -automatically install the Clojure jar in the right place. Leiningen will also -get you a couple more jarfiles, including JLine, which allows you some of the -functionality of readline (command-line history, for example). - -### Installing dependencies - -Dependencies are installed automatically with lein 2, but if you are still -using lein 1 run - -`lein deps` - -which will download all dependencies you need to run the Clojure koans. - - -### Running the Koans - -If you're running from the zipfile or using lein 1, simply run - -`script/run` on Mac/\*nix - -`script\run` on Windows - -If you're running from a checkout using lein 2, run the koans via - -`lein koan run` - -It's an auto-runner, so as you save your files with the correct answers, it will -advance you to the next koan or file (conveniently, all files are prefixed with -the sequence that you should follow). - -You'll see something like this: - - Now meditate on /home/colin/Projects/clojure-koans/src/koans/01_equalities.clj:3 - --------------------- - Assertion failed! - We shall contemplate truth by testing reality, via equality. - (= __ true) - -The output is telling you that you have a failing test in the file named -`01_equalities.clj`, on line 3. So you just need to open that file up and make -it pass! You'll always be filling in the blanks to make tests pass. -Sometimes there could be several correct answers (or even an infinite number): -any of them will work in these cases. - -The koans differ from normal TDD in that the tests are already written for you, -so you'll have to pay close attention to the failure messages, because up until -the very end, making a test pass just means that the next failure message comes -up. - -While it might be easy (especially at first) to just fill in the blanks making -things pass, you should work thoughtfully, making sure you understand why the -answer is what it is. Enjoy your path to Clojure enlightenment! - - -### Trying more things out - -There's a REPL (Read-Evaluate-Print Loop) included in the Clojure Koans. Just -run: - -`script/repl` on Mac/\*nix - -`script\repl` on Windows - -If you're on lein 2, `lein repl` is what you want instead. - -Here are some interesting commands you might try, once you're in a running REPL: - -```clojure -(find-doc "vec") -(find-doc #"vec$") -(doc vec) -``` - -And if those still don't make sense: - -```clojure -(doc doc) -(doc find-doc) -``` - -will show you what those commands mean. - -You can exit the REPL with `CTRL-d` on any OS. - - -### Contributing - -Patches are encouraged! Make sure the answer sheet still passes -(`script/test`, or `script\test` on Windows, or `lein koan test` on lein2), and -send a pull request. - -The file ideaboard.txt has lots of good ideas for new koans to start, or things -to add to existing koans. So write some fun exercises, add your answers to -`resources/koans.clj`, and we'll get them in there! - -Feel free to contact me (Colin Jones / trptcolin) on Github or elsewhere if you -have any questions or want more direction before you start pitching in. - - -### Contributors - -https://github.com/functional-koans/clojure-koans/contributors - - -### Credits - -These exercises were started by [Aaron Bedra](http://github.com/abedra) of -[Relevance, Inc.](http://github.com/relevance) in early 2010, as a learning -tool for newcomers to functional programming. Aaron's macro-fu makes these -koans extremely simple and fun to use, and to improve upon, and without -Relevance's initiative, this project would not exist. - -Using the [koans](http://en.wikipedia.org/wiki/koan) metaphor as a tool for -learning a programming language started with the -[Ruby Koans](http://rubykoans.com) by [EdgeCase](http://github.com/edgecase). - - -### License - -The use and distribution terms for this software are covered by the -Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) -which can be found in the file epl-v10.html at the root of this distribution. -By using this software in any fashion, you are agreeing to be bound by -the terms of this license. +Simple solutions to the excellent clojure-koans. Putting them here for a simple reference during brain farts. From 2e0b4e4760c99894a39d7b4ef161bc1dd577e4e7 Mon Sep 17 00:00:00 2001 From: Manas Karekar Date: Sun, 3 Mar 2013 16:36:43 -0500 Subject: [PATCH 4/6] Exercise 9 - runtime polymorphism --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 991bedd..dfedf83 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -Simple solutions to the excellent clojure-koans. Putting them here for a simple reference during brain farts. +Simple solutions to the excellent clojure-koans. Putting them here as a quick reference during brain farts. From abea3219fb7cd865799a22e2fc403cb7c3ffe977 Mon Sep 17 00:00:00 2001 From: Manas Karekar Date: Sun, 3 Mar 2013 19:32:09 -0500 Subject: [PATCH 5/6] README updated --- README.md | 4 +++- src/koans/09_runtime_polymorphism.clj | 12 ++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f3cd403..5c04336 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,9 @@ The output is telling you that you have a failing test in the file named `01_equalities.clj`, on line 3. So you just need to open that file up and make it pass! You'll always be filling in the blanks to make tests pass. Sometimes there could be several correct answers (or even an infinite number): -any of them will work in these cases. +any of them will work in these cases. Some tests will pass even if you replace the +blanks with whitespace or nothing instead of the expected answer. Make sure you +give one correct expression to replace each blank. The koans differ from normal TDD in that the tests are already written for you, so you'll have to pay close attention to the failure messages, because up until diff --git a/src/koans/09_runtime_polymorphism.clj b/src/koans/09_runtime_polymorphism.clj index a8171ee..37816e7 100644 --- a/src/koans/09_runtime_polymorphism.clj +++ b/src/koans/09_runtime_polymorphism.clj @@ -7,19 +7,19 @@ "!"))) (defmulti diet (fn [x] (:eater x))) -(defmethod diet :herbivore [a] __) -(defmethod diet :carnivore [a] __) -(defmethod diet :default [a] __) +(defmethod diet :herbivore [a] (str (:name a) " eats veggies.")) +(defmethod diet :carnivore [a] (str (a :name) " eats animals.")) +(defmethod diet :default [a] (str "I don't know what " (:name a) " eats.")) (meditations "Some functions can be used in different ways - with no arguments" - (= __ (hello)) + (= "Hello World!" (hello)) "With one argument" - (= __ (hello "world")) + (= "Hello, you silly world." (hello "world")) "Or with many arguments" - (= __ + (= "Hello to this group: Peter, Paul, Mary!" (hello "Peter" "Paul" "Mary")) "Multimethods allow more complex dispatching" From 1e4aba60ccc8be7f9fccc5016a5476777304dd5b Mon Sep 17 00:00:00 2001 From: Manas Karekar Date: Sun, 3 Mar 2013 20:06:45 -0500 Subject: [PATCH 6/6] Updated README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5c04336..28f1a95 100644 --- a/README.md +++ b/README.md @@ -68,9 +68,9 @@ The output is telling you that you have a failing test in the file named `01_equalities.clj`, on line 3. So you just need to open that file up and make it pass! You'll always be filling in the blanks to make tests pass. Sometimes there could be several correct answers (or even an infinite number): -any of them will work in these cases. Some tests will pass even if you replace the -blanks with whitespace or nothing instead of the expected answer. Make sure you -give one correct expression to replace each blank. +any of them will work in these cases. Some tests will pass even if you replace +the blanks with whitespace or nothing instead of the expected answer. Make sure +you give one correct expression to replace each blank. The koans differ from normal TDD in that the tests are already written for you, so you'll have to pay close attention to the failure messages, because up until