- Study Clojure.core daily
- Read "Joy of Clojure" The Joy of Clojure
- Code, Code, and Code in Clojure as much as you can
(def
my-assoc
(fn my-assoc
([map key val] (assoc map key val))
([map key val & kvs]
(let [ret (my-assoc map key val)]
(if kvs
(recur ret (first kvs) (second kvs) (nnext kvs))
ret)))))
(println (my-assoc {} :symbol "assoc")) => {:symbo assoc}
my-assoc here is a Var that holds a reference to a function that named my-assoc, which takes a map and one or more key-val pairs, and returns a map that contains the mapping. This actually is a classic Clojure style of tail recursive function. Namely, it is an idiomatic way to use function signatures for base and recursive cases. It is also very elegant to use let binding to hold accumulative value that will be referred in multiple places in a block. The use of recur in the tail position is just what it is intended for. It recursively invokes my-assoc function with the correct number of arguments, which in this case
(my-assoc [map key val & kvs]) until kvs are nil, which is one of only two false (nil and false) in idiomatic Clojure. (first kvs) (second kvs) (nnext kvs) is also idiomatic way of traversing a seq that will save you from unexpected nil punning. (Again, read "Joy of Clojure" for detailed explanation for this).
My way of learning idiomatic Clojure is very opinionated and might not work for everyone. What is your way of learning idiomatic Clojure? Please share it if you can so a Clojure noob will have a good start.
Beware that core.clj is not always the most idiomatic: up to the redefinition of let to use destructuring most of the language is missing, then there is some legacy style (eg old interop with plain dot instead of .method and Foo/bar).
ReplyDeleteThanks for pointing this out. I will keep this in mind.
ReplyDelete