Starting code in Clojure (and functional languages) is confusing for beginners


#1

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?


#2

The poor quality of the Clojure’s stub has already been reported before.

Here:
https://www.codingame.com/forum/t/expected-clojure-template/2737/2
and here:
https://www.codingame.com/forum/t/clojure-main-function-should-be-optional/50106

I’ll push again to see what can be done.

On CodinGame, the default code is generated from the stub generator, a program that generates the default codes in all the languages from 1 set of instructions. We can override the generated default code for any language though.
For example, here is what it looks like for Horse Racing Duals:

read N:int
loop N read Pi:int
write answer

I’m not sure what we will be able to change, either in the generator or directly per puzzle. I’m pushing internally for a language update before the next challenge (due in October), so maybe this could be a part of it.


#3

@_CG_Thibaud, maybe the stub generator could be published on github? That would make it possible for the community to send pull requests to improve it for a specific language.