Search code examples
clojure

4clojure #58 (compose)... stuck


trying to do compose (#58)

(defn compose [& fns]
  (fn [a & opts]
    (if opts
      ;println can be removed, just shows my confusion
      (reduce (fn [x y] (println(apply y (list x))) (apply y (list x))) (cons a opts) (reverse fns)))
      (reduce (fn [x y] (y x)) a (reverse fns))))

((compose rest reverse) 1 2 3 4)

I've killed too much time on this so I'm resorting to asking for help... I've only got about 2-3 days experience so forgive the ugly clojure and the most likely unnecessary if form. I'd like to know what is wrong with this, as opposed to getting a completely different (and I'm sure nicer) answer.

What's confusing me is that the error is indicating I am trying to call a list as a function, but the print statement is showing exactly the results I would expect, using the same code as the function body.


Solution

  • I think you just got your parens in the wrong place. This works:

    (defn compose [& fns]
      (fn [a & opts]
        (if opts
          (reduce (fn [x y] (apply y (list x))) (cons a opts) (reverse fns))
          (reduce (fn [x y] (y x)) a (reverse fns)))))
    

    It was easy for me to see the problem right away because I use an editor that understands about parens and alignment - I just put your code in IntelliJ/Cursive. Cursive uses structural editing (otherwise known as Paredit).

    Also when debugging be aware that println returns nil. I often use a probe function for this kind of debugging:

    (defn probe-on
      ([x]
       (println x)
       x)
      ([x msg]
       (println msg x)
       x))
    

    , but you can now (or coming, they are still a little new) get editors/debuggers that don't require you to use such debugging techniques. See proto-REPL and Sayid.