Exploring Clojure with factorial computation.
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.


Exploring Clojure with Factorial Computation

This project demonstrates a variety of of Clojure language features and library functions using factorial computation as an example.

Many Clojure tutorials (and CS textbooks, for that matter) use factorial computation to teach recursion. I implemented such a function in Clojure and thought: "why stop there?"


Approaches used to calculate factorials:

  1. Using loop and recur
  2. Using reduce and range
  3. Using apply and range
  4. Using apply take and iterate
  5. Using reduce and range but returning a fn (a "higher-order" factorial function)
  6. Using defmacro to create a function that always calculates the same factorial.
  7. Using cons range and eval
  8. Parallel computation using future dosync and alter
  9. Parallel computation using ref agent send and await
  10. Parallel computation using reduce and pmap
  11. Extremely convoluted parallel computation using reduce and pvalues (requiring a macro)
  12. Yet more convoluted parallel computation using reduce and pcalls (also requiring a macro)
  13. By getting the nth value from a lazy-seq of factorials.
  14. Using trampoline and mutually-recursive functions defined with letfn.
  15. Using defmethod defmulti and defrecord (plus update-in and ->) for recursive computation.
  16. Using a Java primitive array and areduce
  17. Using Java interop to call a Java class.
  18. Using Java interop, but with -> to tame a goofy "Builder" pattern.
  19. Using reify to implement a pre-existing Java interface using one of our previous functions.
  20. Using incanter.core/factorial (duh!)

Hall of Shame

Buggy or just wrong functions that still "work."

  1. (Mis-)using def do and dotimes (defective code)
  2. (Mis-)using def do and while (yet more defective code)
  3. (Mis-)using while atom and swap (not precisesly defective, but not a good use of Atoms).
  4. An attempt with agent and recursive send-off calls, which often fails due to a race condition with await


This project builds with Leiningen 2. Note that it includes some Java sources (for the interop examples).

Running lein test or lein repl will compile said Java sources.

Also, the source code comments are formatted for Marginalia. Configure your profile to use the lein-marginalia plugin and run lein marg to generate documentation.

GitHub Page

This project also has a GitHub page hosting the generated Marginalia documentation (with some manual tweaks). Point your browser to


Continuous Integration

Build Status

CI is hosted by travis-ci.org


Creative Commons CC0 1.0 Universal

See: http://creativecommons.org/publicdomain/zero/1.0/legalcode

Noah Zucker (nzucker at gmail.com / @noahlz)