noahlz/factorials

Exploring Clojure with factorial computation.
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.
src
.gitignore
.travis.yml
project.clj

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?"

Inventory

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`

Building

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

http://noahlz.github.io/factorials

Continuous Integration

CI is hosted by travis-ci.org