The Beauty of Clojure

This post is biased but I happen to like and agree with my biases so take everything written below with a grain of salt.

Clojure is one of my favorite programming languages because of its philosophy of handling state, functional programming, immutable data structures and of course macros.

However, after using component for a project at work, I noticed that my code stopped looking like idiomatic Clojure code and more like OO Java I used to write. While features like reify, defprotocol, deftype, and defrecord exist they exist for the purposes interop with Java, type extensions and library APIs. In my opinion the bulk of Clojure code should strive to utilize functions and be data oriented.

Clearly, with around 1,000 stars on GitHub, many people find component useful, but its object-oriented paradigm feels unnatural and at odds with the way Clojure is written. The rising popularity of component alarms me because looking at some of the code I and others have produced leaves little room for idiomatic Clojure.

Today I ran across a great blog post by Christopher Bui that reminded me of why I avoid component instead opting for mount. The best part of it is that it included code that enables me to rant by writing code which is my favorite kind of ranting.

As an exercise I decided to rewrite Christopher’s component code using mount and I am quite happy with the results.

Here’s the description of the original task:

Let’s say you’re planning on building a new service for managing emails in your application. The work involved is taking messages off of a queue, doing some work, writing data to a database, and then putting things onto other queues. Everything will be asynchronous.

My Clojure code using component looks very similar to the one written by the Christopher because protocols and records end up being at the forefront when they should be de-emphasized, as they are in my mount example. Functions, which are in the background using component are featured in the mount code below.

I have the full example shipper project on github that models an warehouse system that:

  1. reads order numbers that are ready to ship off of a warehouse queue
  2. sends out email notifications to customers
  3. writes order status changes and emails to DB
  4. and then sends notifications to postal to start a shipping process

Below is all the code on one page with namespace declarations removed. A real runnable version is available in the GitHub repo above.

Outside of ‘defstate’s which work like regular ‘def’ variables everything is a function. In my opinion, the above looks more idiomatic and I find it easier to read than the componentized version. In my experience mount’ed code ends up being shorter as a bonus. A big takeaway from using mount is that you can require defstate variables like you would any other var in a namespace and it just works. Take a look at the repo for examples.

Here’s how to interact with the code in boot/lein REPL session.

In short I encourage everyone to keep Clojure idiomatic and beautiful and just because your code has state it doesn’t mean you have to abandon the way you structure your programs.

sin(n) = -1 where n is an integer in radians

I saw a fun math problem on reddit the other day.

find a number n, so that sin(n)=-1, where n is an integer in radians; so sin(270 degrees) doesn’t count. Obviously it will never be exactly -1 but close enough for the difference to be lost in rounding.

\sin(\frac{3\pi}{2} + 2\pi \cdot n) = -1
I need the argument of sin function to be as close to an integer as possible. Call this integer m.
\frac{3\pi}{2}+2\pi \cdot n \approx m
Solving for \pi leads to:
\pi \approx \frac{p}{q} \approx \frac{2m}{4n+3}

If I have a rational approximation to \pi with an even numerator I can divide it by two get my m. I also have to make sure that the denominator is in the form of 4n+3.
It’s possible to use continued fractions to approximate real numbers. Here’s a continued fraction sequence for pi: https://oeis.org/A001203

The first rational approximation I learned in elementary school is 22/7 which is perfect.

> (sin 11)
-.9999902065507035

For the others I’ll have to evaluate the continued fraction to get my approximation of a simple fraction.

> (eval-terms (list 3 7 15 1 292 1))
104348/33215

> (sin (/ 104348 2))
-.9999999999848337

> (eval-terms (list 3 7 15 1 292 1 1 1 2 1 3 1 14 2 1))
245850922/78256779

> (sin (/ 245850922 2))
-.99999999999999999532
Looks like a good candidate was found.

This is the code to evaluate a continued fraction coefficients. It’s very convenient that scheme has a native rational data type.

Exercise 2.42 of SICP

Exercise 2.42:

A solution to the eight-queens puzzle.

A solution to the eight-queens puzzle.

The “eight-queens puzzle” asks how to place eight queens on a chessboard so that no queen is in check from any other (i.e., no two queens are in the same row, column, or diagonal). One possible solution is shown in figure 2.8. One way to solve the puzzle is to work across the board, placing a queen in each column. Once we have placed k – 1 queens, we must place the kth queen in a position where it does not check any of the queens already on the board. We can formulate this approach recursively: Assume that we have already generated the sequence of all possible ways to place k – 1 queens in the first k – 1 columns of the board. For each of these ways, generate an extended set of positions by placing a queen in each row of the kth column. Now filter these, keeping only the positions for which the queen in the kth column is safe with respect to the other queens. This produces the sequence of all ways to place k queens in the first k columns. By continuing this process, we will produce not only one solution, but all solutions to the puzzle.

We implement this solution as a procedure queens, which returns a sequence of all solutions to the problem of placing n queens on an n×n chessboard. Queens has an internal procedure queen-cols that returns the sequence of all ways to place queens in the first k columns of the board.

In this procedure rest-of-queens is a way to place k – 1 queens in the first k – 1 columns, and new-row is a proposed row in which to place the queen for the kth column. Complete the program by implementing the representation for sets of board positions, including the procedure adjoin-position, which adjoins a new row-column position to a set of positions, and empty-board, which represents an empty set of positions. You must also write the procedure safe?, which determines for a set of positions, whether the queen in the kth column is safe with respect to the others. (Note that we need only check whether the new queen is safe — the other queens are already guaranteed safe with respect to each other.)

> (length (queens 8))
92
> (length (queens 11))
2680
> (length (queens 10))
724
> (queens 4)
((2 4 1 3) (3 1 4 2))

Exercise 2.40 of SICP

Exercise 2.40: Define a procedure unique-pairs that, given an integer n, generates the sequence of pairs (i,j) with latex path not specified.: 1\le j< i\le n[/latex]. Use unique-pairs to simplify the definition of prime-sum-pairs given above.

Using Miller-Rabin primality test as well as taking advantage of some lexical scoping here is the solution:

> (prime-sum-pairs 1)
()
> (prime-sum-pairs 2)
((2 1 3))
> (prime-sum-pairs 3)
((2 1 3) (3 2 5))
> (prime-sum-pairs 4)
((2 1 3) (3 2 5) (4 1 5) (4 3 7))
> (prime-sum-pairs 5)
((2 1 3) (3 2 5) (4 1 5) (4 3 7) (5 2 7))

Exercise 2.39 of SICP

Exercise 2.39: Complete the following definitions of reverse (exercise 2.18) in terms of fold-right and fold-left from exercise 2.38:

> (reverse-right (list 1 2 3))
(3 2 1)
> (reverse-left (list 1 2 3))
(3 2 1)

Exercise 2.38 of SICP

Exercise 2.38: The accumulate procedure is also known as fold-right, because it combines the first element of the sequence with the result of combining all the elements to the right. There is also a fold-left, which is similar to fold-right, except that it combines elements working in the opposite direction:

What are the values of

3/2

1/6

(1 (2 (3 ())))

(((() 1) 2) 3)
Give a property that op should satisfy to guarantee that fold-right and fold-left will produce the same values for any sequence.
(fold-right op i (list a1 a2 a3))
(a_1 \cdot (a_2 \cdot ( a_3 \cdot i)))
(fold-left op i (list a1 a2 a3))
(((i \cdot a_1) \cdot a_2) \cdot a_3)

Any binary associative operation will be invariant under fold-right and fold-left.

Since 2.37 involved matrix multiplication which is associative, I will use that as an example.
> (define i (list (list 1 0 0) (list 0 1 0) (list 0 0 1)))
> (define a1 (list (list 8 3 2) (list 1 0 9) (list 3 4 5)))
> (define a2 (list (list 5 6 7) (list 1 2 8) (list 6 7 7)))
> (define a3 (list (list 6 7 9) (list 4 3 1) (list 3 4 5)))
> (fold-left matrix-*-matrix i (list a1 a2 a3))
((884 965 1033) (840 900 950) (802 878 942))
> (fold-right matrix-*-matrix i (list a1 a2 a3))
((884 965 1033) (840 900 950) (802 878 942))

Notice that i is the identity matrix because if it wasn’t, I would also be testing commutativity of matrix product. Matrix product doesn’t commute. If i is changed to another matrix fold-left and fold-right will return differing results.

Exercise 2.37 of SICP

Exercise 2.37: Suppose we represent vectors v=(v_i) as sequences of numbers, and matrices m = (m_{ij}) as sequences of vectors (the rows of the matrix). For example, the matrix

M = \begin{bmatrix} 1&2&3&4\\ 4&5&6&6\\ 6&7&8&9 \end{bmatrix}

is represented as the sequence ((1 2 3 4) (4 5 6 6) (6 7 8 9)). With this representation, we can use sequence operations to concisely express the basic matrix and vector operations. These operations (which are described in any book on matrix algebra) are the following:

We can define the dot product as:

Fill in the missing expressions in the following procedures for computing the other matrix operations. (The procedure accumulate-n is defined in exercise 2.36.)

Solutions:

> (define n (list (list 1 2) (list 3 4)))
> (matrix-*-vector n (list 10 20))
(50 110)
> (transpose n)
((1 3) (2 4))
> (define m (list (list 1 2 3) (list 4 5 6) (list 7 8 9)))
> (matrix-*-matrix m m)
((30 36 42) (66 81 96) (102 126 150))
> (define q (list (list 9 1) (list 3 4) (list 6 7) (list 1 8)))
> (matrix-*-matrix (list (list 1 2 3 4) (list 5 6 7 8)) q)
((37 62) (113 142))

Exercise 2.36 of SICP

Exercise 2.36: The procedure accumulate-n is similar to accumulate except that it takes as its third argument a sequence of sequences, which are all assumed to have the same number of elements. It applies the designated accumulation procedure to combine all the first elements of the sequences, all the second elements of the sequences, and so on, and returns a sequence of the results. For instance, if s is a sequence containing four sequences, ((1 2 3) (4 5 6) (7 8 9) (10 11 12)), then the value of (accumulate-n + 0 s) should be the sequence (22 26 30). Fill in the missing expressions in the following definition of accumulate-n:

> (define s (list (list 1 2 3) (list 4 5 6) (list 7 8 9) (list 10 11 12)))
> (accumulate-n + 0 s)
(22 26 30)

Exercise 2.35 of SICP

Exercise 2.35: Redefine count-leaves from section 2.2.2 as an accumulation:

The goal here is for map to create something that accumulate can consume to count the number of leaves. The initial value must be 0 just like in count-leaves. The hard part is to come up with fn that will add up the leaves. If the tree is flatted a simple length function will compute the number of trees.

I am not sure why map is needed in this example. It just serves to confuse. The lambda argument is really a throw away.
I am aware that it is possible to solve this problem using map in a way that recursively calls count-leaves. I feel like instead of making the computational process clearer as in square-tree and even-fibs it becomes more convoluted and mysterious. Nevertheless I include it bellow for completeness.

The example I like is: