I’ve heard newcomers to Clojure ask how to get started with functional programming. I believe that learning to program in the functional style is mostly a matter of practice. The newcomer needs to become familiar with a handful of higher order functions, and how they are used in common idioms. This can be done by practice with simple, well defined problems. I assume that the prospective reader already has a grasp of the rudiments of Clojure, and can operate the Leiningen build tool.
Here is what I propose. I have prepared a set of annotated exercises illustrating typical Clojure fp idioms. The exercises are the first 31 Project Euler problems, one for each day of the month. I believe these problems are ideal for the purpose at hand. Each problem is succinctly stated, interesting, and well defined. Each lends itself to a natural functional solution.
I have packaged the problems as a Leiningen project. Each problem is stated, and then solved. Each problem is in its own name space, to enable code reuse across problems. Each problem is documented using the fabulous Marginalia literate programming tool. Running commentary tries to point out common idioms, and provides links to ClojureDocs documentation for newly introduced functions. Unit tests are provided to check the provided solution against the official Project Euler solution. The solutions use current Clojure (1.4.0 beta). Nothing is used from the old clojure.contrib. Each solution is written in an explicitly functional style. Many of the solutions consist solely of function definitions. Vars are used only to name data given as part of a problem statement, or data structures constructed from such data. All data is treated as immutable.
What I recommend is deceptively simple. Read each problem statement. Think about how you might solve it; do so if you like. Then read the provided solution. Read it actively: take the time to run the code, and to understand every function and every construct in the solution. Play with the code. Make changes, run things in the repl. Use ‘lein test’ to see whether your modifications still get the same answer.
Here’s the important point: once you understand the solution, delete it and then reconstruct it. Type it in. Look up functions you don’t remember. Did I mention you should type the code in? Knowledge enters the mind through the fingers, not just the eyes. Do this and I believe you will quickly jump-start your understanding of functional programming in Clojure.
Here are a few things to avoid.
Do not attempt to learn Clojure and new tooling, say Emacs+slime, at the same time. Keep it simple. Edit code using whatever editor you normally use, and run a Clojure repl in whatever terminal emulator you normally use. No fancy IDE or editor hacking is required. Separation of concerns applies to learning as much as to coding.
Don’t worry about parts of Clojure not immediately related to functional programming. In particular, don’t worry about concurrency constructs, STM, protocols, multi-methods, macros, transients, or whatever. Instead, worry about knowing how to define functions using any and all of (defn …), (def …), #(…), and (fn …). Learn map, filter, reduce, for, let, letfn, and iterate.
The Project Euler problems do require a bit of math. Don’t let that put you off. Worst comes to worst, I have already done the math for you. The goal here is to learn fp not math, so don’t get hung up on solving the problems ab initio. The problems are a device to present solutions written in a functional style. If a particular problem hangs you up, skip it.
Don’t worry about lambda calculus, type theory, category theory, monads, morphisms, or any such abstract concerns. Your functional programming journey may eventually take you to those, but you need not start there. Abstraction is best appreciated in the light of experience with concrete examples. Begin by reading and writing code to solve many small, concrete problems. See what the solutions have in common. That is what you want to learn. The more these solutions seem like variations on a theme, the better.
When I first started learning Clojure, I did so by working Project Euler problems. PE is a lovely and tasteful collection of problems, one that has provided countless hours of instruction and fun to many, many people. While the PE problems are outstanding, I do not claim any special virtue for my solutions. But they should not require any special virtue, that is the point. I want you to see functional programming as a simple and natural way to express intent, as one more way to get things done. If these solutions seem routine, then I have done what I set out to do.