Thursday, February 24, 2011

Clojure partition-at

While working with some code, I noticed what appears to be a missing function. I wanted to use something like partition-by, which splits the collection each time the passed function returns a new value. Except I wanted it to split whenever the passed function returns true, instead of when the return value changes. Anyways, here it is:



(defn partition-at
"Like partition-by but will start a new run when f returns true"
[f coll]
(lazy-seq
(when-let [s (seq coll)]
(let [run (cons (first s) (take-while #(not (f %)) (rest s)))]
(cons run (partition-at f (drop (count run) s)))))))

Clojure functions need default parameters

So, I have decided to learn the clojure programming language and realized that this was a good place to document the things I learn.

The first thing I found out was that clojure doesn't support default parameters out of the box. So, as step one in learning clojure, I built a new defn that supports default parameters called defo and threw it up on GitHub. It came in useful as I am working my way though the 99 Lisp Problems

Now, instead of writing:


(defn foo
([x] (foo x 1))
([x y] (foo x y y))
([x y z] (+ x y z)))

I can now write:



(defo foo [x (y 1) (z y)] (+ x y z)

Optional parameters are embedded in parenthesis, with the name being followed by what the default value will be.

Apparently recur calls don't roll their args into the final & argument so this causes an error:


(defn go-to-zero [& col]
(let [f (first col)])
(if (= 0 f)
(println "done")
(recur (dec f))))
(go-to-zero 3)

So there is a part of the macro that would re-write the recur call, placing the final parameters into a list so it doesn't throw errors.