So, I’m a beginner at Clojure, so I might be getting this wrong, but it seems like most of the starting code provided when you pick Clojure for most problems is confusing and useless.
Take this from one of the easy puzzles, Horse-Racing Duels:
(let [N (read)]
(loop [i N]
(when (> i 0)
(let [Pi (read)]
(recur (dec i)))))
The problem requires all these items to be read and stored in a list. Thing is, because of Clojure’s functional nature there’s nothing you can put inside that loop to build such a list. As far as I can see at the very least you’d have to add the accumulating list to loop
and wrap the whole thing in a let
, like this:
(let [N (read)
horses (loop [i N h []]
(if (> i 0)
(let [Pi (read)]
(recur (dec i) (cons Pi h)))
h))]
(println horses)))
That’s a pretty significant change to what you’re being given as an exemplar. And even that’s pretty horrible, and all the actual solutions from good Clojure programmers don’t use anything like this structure, solving the whole thing with (repeatedly read (read))
.
As a beginner I spent a lot of time confused as to how I was supposed to get a list out of this structure when actually the problem is that the structure is a blind port of the similar code from imperative languages. The comment says that the “auto-generated code is to help you parse the input” but it doesn’t help in this case, it sends you almost exactly wrong.
(After seeing this I went and looked at the example for Haskell, another language I do know, and it’s slightly better - it uses replicateM
to build a list - but then it chucks that list away because it’s not assigned to anything nor part of a function called by the final output statement.)
Could the cases be improved for these languages?