I don't know if this is just their test runner or whether it is a problem in Clojure proper, but it's really frustrating to see "Assertion failed" with zero description of the runtime error. I have to fire up a REPL and reverse engineer the expected value, instead of just observing what the expression evaluates to as in the ruby koans.
As an example:
"But watch out if you try to pop nothing"
(= __ (try
(pop '())
(catch IllegalStateException e "No dice!")))
That code causes an error that looks like this:
Problem in /home/clueless/clojure-koans/src/koans/02_lists.clj
---------------------
Assertion failed!
But watch out if you try to pop nothing
(= __ (try (pop (quote ())) (catch IllegalStateException e "No dice!")))
That's just a transliteration of the Clojure expression from my source code. It's not even as good as a line number, because it's not greppable. If I were actually to encounter this in a failing test, you had better believe I would want to know what the right-hand-side actually evaluated to in context, not just what the compiled expression looks like.
Yeah, I hear you. There's definitely room for improvement here. I'm not sure what you mean by not greppable - the file is listed, as is the name of the particular koan. If there's a way to get line numbers displayed here that would be great.
I agree it does make it easier to solve when you can see what you're trying to evaluate to. It was actually a conscious decision to make that not be the case, because it seemed too easy to just fill in the blanks without thinking about what should go there.
In this case it's a Java wart, yes, but the same thing happens with other parts of the language. Another example:
"Conjoining an element to a list can be done in the reverse order"
(= __ (conj '(:a :b :c :d :e) 0))
Well OK, so is `conj` just `cons` with reversed argument order, or does it append to the other end of the list? My Lisp intuition tells me that the first is more likely, but the test failure doesn't show you anything, you have to use trial and error or fire up a REPL.
There's more to conj. It does a cons for lists, but works differently for other types of collections. You might find it helpful to lookup things in ClojureDocs. http://clojuredocs.org/clojure_core/clojure.core/conj
Not really either. Conj acts on collections (which can be lists, vectors, sets or hash maps), and adds the second and subsequent arguments to the collection in a type-dependent way. For a list, your hunch is correct, in that it's a bit like a reversed-argument 'cons', except that you can have add more than one item to the list;
Exercises on http://www.4clojure.com seem like a much easier way to get your feet wet with Clojure. It's good when new users can try a language out right in their browsers, without having to install any additional software.
I agree that 4clojure.com seems an easier way to get started. However, if you're already setup with Clojure on your machine, using clojurekoans.com has the advantage of allowing you to work in your editor of choice.
Since this is for new Clojure users I think the install instructions should include how to install the koans with Leiningen. The instructions say to install Leiningen but once you've got that working you won't know how to use it to install the koans.
I agree, it's a bit confusing how it's written, and I'm not even really sure what using lein would buy you when doing the koans. If anyone is interested in using lein, here's what you need to look at: https://github.com/functional-koans/lein-koan
Specifically:
git clone git@github.com:functional-koans/clojure-koans.git
cd clojure-koans
lein deps
lein koan run
I don't agree, I'd advise not to try Leiningen until you're comfortable enough with the parenthesis, the REPL and finish the koans themselves. This is 'getting your feet wet on Clojure', koans style. No need to introduce yet another tool when you're not dealing with the issues which Leinengen solves: managing library dependencies and configuration.
I remember I did: the koans first, then tried several exercises on the 4clojure website, then learned about Leinengen and only then I moved into 'projects'.
Ok, but the site's first suggestion is to use Leiningen to install the koans. It links to a generic Leiningen installation page, but then doesn't tell you how to use it to install the koans.
Unless they expect the new user to spend significant time learning about that tool before moving on to their koans, I think it'd really be much better to have a short how-to for that.
Learn Leiningen- not only because it makes Clojure simple and pleasurable to use, but because it'd be a fantastic tool no matter what language it was part of.
Project skeletons (new new), command line scripting (via lein exec), deployment, the wonderful 'lein ring server', custom plugins... and for those who just want to get their feet wet, 'lein repl' brings the ocean to you.
My initial reaction was to upvote @eccp, based on my experience with leiningen the first time round. Long story short: went around in circles following outdated (but seemingly comprehensive) guides that twisted my mind with hopeless combinations of Ant, Maven, Leiningen, emacs, slime and swank, among others. Basically gave up after a while, but was fortunate to get some encouragement here on HN, and went back in with just leiningen and emacs. I recall that was just the right mix, and as you say, lein repl pretty much brought the ocean to me.
If you have lein, you can run `lein repl` which provides awesome tab-completions, documentation, and source for any given function. Pretty handy for beginners I'd say!
Right, this needed to be cleaned up and clarified. The only thing you have to do is `lein koan run`, which was listed as an option but the ordering was confusing. I've reworked it a bit now, but feel free to open an issue/PR if things are still hazy: https://github.com/functional-koans/clojure-koans-web
Indeed, I'm trying to wrap my head around it now. It's a shame, this looked like a nice fun way to just drop in to playing around with Clojure, but it turns out that it's being bit of a hassle. Not that I don't think there should be a little effort involved! It's just that my expectations did not match up to reality.
This is the first time I've seen something like this, but it's greatly broadened my knowledge of Clojure over the past few hours. I've always had trouble trying to find out where to begin. Lisps are foreign to me, and functional programming was and is still a mostly foreign concept. However, things like this that are so simple and understandable make such great introductions.
Kudos to the authors, and you have a thumbs up from me.
As a somewhat recent practicer of tdd, I find that the koans + tdd approach is more rounded: I'm forced to learn/use a function/aspect that I might have glossed over. And occasionally a particularly nice usage of syntax jumps out and gets adopted.
Does anyone know how to run these in Light Table? I really love the idea of that and was hoping to try it to learn Clojure, but I have absolutely no idea how to run the koans from inside Light Table.
I did 'lein koan run' in my terminal and opened the first file up in LightTable, then made my first edit and hit save - the terminal updated automatically as I saved my changes.
I did a few Project Euler (http://projecteuler.net) problems in Clojure after doing the koans. I found it really helpful to implement solutions in some imperative or multi-paradigm language, and then go back and do the solutions again in Clojure. Each problem made me curious about the best way to solve it in Clojure, which led to lots of learning.
I was playing with the Rosalind problems using clojure. It was great fun, although I did evil things with the clojure combinatorics library and in one memorable session, datomic datalog.
I need to revisit them, but the thornier (for me) problems kept distracting me from other work.
As an example:
That code causes an error that looks like this: That's just a transliteration of the Clojure expression from my source code. It's not even as good as a line number, because it's not greppable. If I were actually to encounter this in a failing test, you had better believe I would want to know what the right-hand-side actually evaluated to in context, not just what the compiled expression looks like.