On Clojure

March 23, 2009

A monad tutorial for Clojure programmers (part 3)

Filed under: Libraries — khinsen @ 2:10 pm

Before moving on to the more advanced aspects of monads, let’s recapitulate what defines a monad (see part 1 and part 2 for explanations):

  1. A data structure that represents the result of a computation, or the computation itself. We haven’t seen an example of the latter case yet, but it will come soon.
  2. A function m-result that converts an arbitrary value to a monadic data structure equivalent to that value.
  3. A function m-bind that binds the result of a computation, represented by the monadic data structure, to a name (using a function of one argument) to make it available in the following computational step.

Taking the sequence monad as an example, the data structure is the sequence, representing the outcome of a non-deterministic computation, m-result is the function list, which converts any value into a list containing just that value, and m-bindis a function that executes the remaining steps once for each element in a sequence, and removes one level of nesting in the result.

The three ingredients above are what defines a monad, under the condition that the three monad laws are respected. Some monads have two additional definitions that make it possible to perform additional operations. These two definitions have the names m-zero and m-plus. m-zero represents a special monadic value that corresponds to a computation with no result. One example is nil in the maybe monad, which typically represents a failure of some kind. Another example is the empty sequence in the sequence monad. The identity monad is an example of a monad that has no m-zero.

m-plus is a function that combines the results of two or more computations into a single one. For the sequence monad, it is the concatenation of several sequences. For the maybe monad, it is a function that returns the first of its arguments that is not nil.

There is a condition that has to be satisfied by the definitions of m-zero and m-plus for any monad:

(= (m-plus m-zero monadic-expression)
   (m-plus monadic-expression m-zero)
   monadic-expression)

In words, combining m-zero with any monadic expression must yield the same expression. You can easily verify that this is true for the two examples (maybe and sequence) given above.

One benefit of having an m-zero in a monad is the possibility to use conditions. In the first part, I promised to return to the :when clauses in Clojure’s for forms, and now the time has come to discuss them. A simple example is

(for [a (range 5)
      :when (odd? a)]
  (* 2 a))

The same construction is possible with domonad:

(domonad sequence
  [a (range 5)
   :when (odd? a)]
  (* 2 a))

Recall that domonad is a macro that translates a let-like syntax into a chain of calls to m-bind ending in a call to m-result. The clause a (range 5) becomes

(m-bind (range 5) (fn [a] remaining-steps))

where remaining-steps is the transformation of the rest of the domonad form. A :when clause is of course treated specially, it becomes

(if predicate remaining-steps m-zero)

Our small example thus expands to

(m-bind (range 5) (fn [a]
  (if (odd? a) (m-result (* 2 a)) m-zero)))

Inserting the definitions of m-bind, m-result, and m-zero, we finally get

(apply concat (map (fn [a]
  (if (odd? a) (list (* 2 a)) (list))) (range 5)))

The result of map is a sequence of lists that have zero or one elements: zero for even values (the value of m-zero) and one for odd values (produced by m-result). concat makes a single flat list out of this, which contains only the elements that satisfy the :when clause.

As for m-plus, it is in practice used mostly with the maybe and sequence monads, or with variations of them. A typical use would be a search algorithm (think of a parser, a regular expression search, a database query) that can succeed (with one or more results) or fail (no results). m-plus would then be used to pursue alternative searches and combine the results into one (sequence monad), or to continue searching until a result is found (maybe monad). Note that it is perfectly possible in principle to have a monad with an m-zero but no m-plus, though in all common cases an m-plus can be defined as well if an m-zero is known.

After this bit of theory, let’s get acquainted with more monads. In the beginning of this part, I mentioned that the data structure used in a monad does not always represent the result(s) of a computational step, but sometimes the computation itself. An example of such a monad is the state monad, whose data structure is a function.

The state monad’s purpose is to facilitate the implementation of stateful algorithms in a purely functional way. Stateful algorithms are algorithms that require updating some variables. They are of course very common in imperative languages, but not compatible with the basic principle of pure functional programs which should not have mutable data structures. One way to simulate state changes while remaining purely functional is to have a special data item (in Clojure that would typically be a map) that stores the current values of all mutable variables that the algorithm refers to. A function that in an imperative program would modify a variable now takes the current state as an additional input argument and returns an updated state along with its usual result. The changing state thus becomes explicit in the form of a data item that is passed from function to function as the algorithm’s execution progresses. The state monad is a way to hide the state-passing behind the scenes and write an algorithm in an imperative style that consults and modifies the state.

The state monad differs from the monads that we have seen before in that its data structure is a function. This is thus a case of a monad whose data structure represents not the result of a computation, but the computation itself. A state monad value is a function that takes a single argument, the current state of the computation, and returns a vector of length two containing the result of the computation and the updated state after the computation. In practice, these functions are typically closures, and what you use in your program code are functions that create these closures. Such state-monad-value-generating functions are the equivalent of statements in imperative languages. As you will see, the state monad allows you to compose such functions in a way that makes your code look perfectly imperative, even though it is still purely functional!

Let’s start with a simple but frequent situation: the state that your code deals with takes the form of a map. You may consider that map to be a namespace in an imperative languages, with each key defining a variable. Two basic operations are reading the value of a variable, and modifying that value. They are already provided in the Clojure monad library, but I will show them here anyway because they make nice examples.

First, we look at fetch-val, which retrieves the value of a variable:

(defn fetch-val [key]
  (fn [s]
    [(key s) s]))

Here we have a simple state-monad-value-generating function. It returns a function of a state variable s which, when executed, returns a vector of the return value and the new state. The return value is the value corresponding to the key in the map that is the state value. The new state is just the old one – a lookup should not change the state of course.

Next, let’s look at set-val, which modifies the value of a variable and returns the previous value:

(defn set-val [key val]
  (fn [s]
    (let [old-val (get s key)
	  new-s   (assoc s key val)]
      [old-val new-s])))

The pattern is the same again: set-val returns a function of state s that, when executed, returns the old value of the variable plus an updated state map in which the new value is the given one.

With these two ingredients, we can start composing statements. Let’s define a statement that copies the value of one variable into another one and returns the previous value of the modified variable:

(defn copy-val [from to]
  (domonad state-m
    [from-val   (fetch-val from)
     old-to-val (set-val to from-val)]
    old-to-val))

What is the result of copy-val? A state-monad value, of course: a function of a state variable s that, when executed, returns the old value of variable to plus the state in which the copy has taken place. Let’s try it out:

(let [initial-state        {:a 1 :b 2}
      computation          (copy-val :b :a)
      [result final-state] (computation initial-state)]
  final-state)

We get {:a 2, :b 2}, as expected. But how does it work? To understand the state monad, we need to look at its definitions for m-result and m-bind, of course.

First, m-result, which does not contain any surprises: it returns a function of a state variable s that, when executed, returns the result value v and the unchanged state s:

(defn m-result [v] (fn [s] [v s]))

The definition of m-bind is more interesting:

(defn m-bind [mv f]
  (fn [s]
    (let [[v ss] (mv s)]
      ((f v) ss))))

Obviously, it returns a function of a state variable s. When that function is executed, it first runs the computation described by mv (the first ‘statement’ in the chain set up by m-bind) by applying it to the state s. The return value is decomposed into result v and new state ss. The result of the first step, v, is injected into the rest of the computation by calling f on it (like for the other m-bind functions that we have seen). The result of that call is of course another state-monad value, and thus a function of a state variable. When we are inside our (fn [s] ...), we are already at the execution stage, so we have to call that function on the state ss, the one that resulted from the execution of the first computational step.

The state monad is one of the most basic monads, of which many variants are in use. Usually such a variant adds something to m-bind that is specific to the kind of state being handled. An example is the the stream monad in clojure.contrib.stream-utils. (NOTE: the stream monad has not been migrated to the new Clojure contrib library set.) Its state describes a stream of data items, and the m-bind function checks for invalid values and for the end-of-stream condition in addition to what the basic m-bind of the state monad does.

A variant of the state monad that is so frequently used that has itself become one of the standard monads is the writer monad. Its state is an accumulator (any type implementing th e protocol writer-monad-protocol, for example strings, lists, vectors, and sets), to which computations can add something by calling the function write. The name comes from a particularly popular application: logging. Take a basic computation in the identity monad, for example (remember that the identity monad is just Clojure’s built-in let). Now assume you want to add a protocol of the computation in the form of a list or a string that accumulates information about the progress of the computation. Just change the identity monad to the writer monad, and add calls to write where required!

Here is a concrete example: the well-known Fibonacci function in its most straightforward (and most inefficient) implementation:

(defn fib [n]
  (if (< n 2)
    n
    (let [n1 (dec n)
	  n2 (dec n1)]
      (+ (fib n1) (fib n2)))))

Let’s add some protocol of the computation in order to see which calls are made to arrive at the final result. First, we rewrite the above example a bit to make every computational step explicit:

(defn fib [n]
  (if (< n 2)
    n
    (let [n1 (dec n)
	  n2 (dec n1)
	  f1 (fib n1)
	  f2 (fib n2)]
      (+ f1 f2))))

Second, we replace let by domonad and choose the writer monad with a vector accumulator:

(with-monad (writer-m [])

  (defn fib-trace [n]
    (if (< n 2)
      (m-result n)
      (domonad
        [n1 (m-result (dec n))
	 n2 (m-result (dec n1))
	 f1 (fib-trace n1)
	 _  (write [n1 f1])
	 f2 (fib-trace n2)
	 _  (write [n2 f2])
	 ]
	(+ f1 f2))))

)

Finally, we run fib-trace and look at the result:

(fib-trace 3)
[2 [[1 1] [0 0] [2 1] [1 1]]]

The first element of the return value, 2, is the result of the function fib. The second element is the protocol vector containing the arguments and results of the recursive calls.

Note that it is sufficient to comment out the lines with the calls to write and change the monad to identity-m to obtain a standard fib function with no protocol – try it out for yourself!

Part 4 will show you how to define your own monads by combining monad building blocks called monad transformers. As an illustration, I will explain the probability monad and how it can be used for Bayesian estimates when combined with the maybe-transformer.

March 6, 2009

A monad tutorial for Clojure programmers (part 2)

Filed under: Libraries — khinsen @ 1:09 pm

In the first part of this tutorial, I have introduced the two most basic monads: the identity monad and the maybe monad. In this part, I will continue with the sequence monad, which will be the occasion to explain the role of the mysterious m-result function. I will also show a couple of useful generic monad operations.

One of the most frequently used monads is the sequence monad (known in the Haskell world as the list monad). It is in fact so common that it is built into Clojure as well, in the form of the for form. Let’s look at an example:

(for [a (range 5)
      b (range a)]
  (* a b))

A for form resembles a let form not only syntactically. It has the same structure: a list of binding expressions, in which each expression can use the bindings from the preceding ones, and a final result expressions that typically depends on all the bindings as well. The difference between let and for is that let binds a single value to each symbol, whereas for binds several values in sequence. The expressions in the binding list must therefore evaluate to sequences, and the result is a sequence as well. The for form can also contain conditions in the form of :when and :while clauses, which I will discuss later. From the monad point of view of composable computations, the sequences are seen as the results of non-deterministic computations, i.e. computations that have more than one result.

Using the monad library, the above loop is written as

(domonad sequence-m
  [a (range 5)
   b (range a)]
  (* a b))

Since we alread know that the domonad macro expands into a chain of m-bind calls ending in an expression that calls m-result, all that remains to be explained is how m-bind and m-result are defined to obtain the desired looping effect.

As we have seen before, m-bind calls a function of one argument that represents the rest of the computation, with the function argument representing the bound variable. To get a loop, we have to call this function repeatedly. A first attempt at such an m-bind function would be

(defn m-bind-first-try [sequence function]
  (map function sequence))

Let’s see what this does for our example:

(m-bind-first-try (range 5)  (fn [a]
(m-bind-first-try (range a)  (fn [b]
(* a b)))))

This yields (() (0) (0 2) (0 3 6) (0 4 8 12)), whereas the for form given above yields (0 0 2 0 3 6 0 4 8 12). Something is not yet quite right. We want a single flat result sequence, but what we get is a nested sequence whose nesting level equals the number of m-bind calls. Since m-bind introduces one level of nesting, it must also remove one. That sounds like a job for concat. So let’s try again:

(defn m-bind-second-try [sequence function]
  (apply concat (map function sequence)))

(m-bind-second-try (range 5)  (fn [a]
(m-bind-second-try (range a)  (fn [b]
(* a b)))))

This is worse: we get an exception. Clojure tells us:

java.lang.IllegalArgumentException: Don't know how to create ISeq from: Integer

Back to thinking!

Our current m-bind introduces a level of sequence nesting and also takes one away. Its result therefore has as many levels of nesting as the return value of the function that is called. The final result of our expression has as many nesting values as (* a b) – which means none at all. If we want one level of nesting in the result, no matter how many calls to m-bind we have, the only solution is to introduce one level of nesting at the end. Let’s try a quick fix:

(m-bind-second-try (range 5)  (fn [a]
(m-bind-second-try (range a)  (fn [b]
(list (* a b))))))

This works! Our (fn [b] ...) always returns a one-element list. The inner m-bind thus creates a sequence of one-element lists, one for each value of b, and concatenates them to make a flat list. The outermost m-bind then creates such a list for each value of a and concatenates them to make another flat list. The result of each m-bind thus is a flat list, as it should be. And that illustrates nicely why we need m-result to make a monad work. The final definition of the sequence monad is thus given by

(defn m-bind [sequence function]
  (apply concat (map function sequence)))

(defn m-result [value]
  (list value))

The role of m-result is to turn a bare value into the expression that, when appearing on the right-hand side in a monadic binding, binds the symbol to that value. This is one of the conditions that a pair of m-bind and m-result functions must fulfill in order to define a monad. Expressed as Clojure code, this condition reads

(= (m-bind (m-result value) function)
   (function value))

There are two more conditions that complete the three monad laws. One of them is

(= (m-bind monadic-expression m-result)
   monadic-expression)

with monadic-expression standing for any expression valid in the monad under consideration, e.g. a sequence expression for the sequence monad. This condition becomes clearer when expressed using the domonad macro:

(= (domonad
     [x monadic-expression]
      x)
   monadic-expression)

The final monad law postulates associativity:

(= (m-bind (m-bind monadic-expression
                   function1)
           function2)
   (m-bind monadic-expression
           (fn [x] (m-bind (function1 x)
                           function2))))

Again this becomes a bit clearer using domonad syntax:

(= (domonad
     [y (domonad
          [x monadic-expression]
          (function1 x))]
     (function2 y))
   (domonad
     [x monadic-expression
      y (m-result (function1 x))]
     (function2 y)))

It is not necessary to remember the monad laws for using monads, they are of importance only when you start to define your own monads. What you should remember about m-result is that (m-result x) represents the monadic computation whose result is x. For the sequence monad, this means a sequence with the single element x. For the identity monad and the maybe monad, which I have presented in the first part of the tutorial, there is no particular structure to monadic expressions, and therefore m-result is just the identity function.

Now it’s time to relax: the most difficult material has been covered. I will return to monad theory in the next part, where I will tell you more about the :when clauses in for loops. The rest of this part will be of a more pragmatic nature.

You may have wondered what the point of the identity and sequence monads is, given that Clojure already contains fully equivalent forms. The answer is that there are generic operations on computations that have an interpretation in any monad. Using the monad library, you can write functions that take a monad as an argument and compose computations in the given monad. I will come back to this later with a concrete example. The monad library also contains some useful predefined operations for use with any monad, which I will explain now. They all have names starting with the prefix m-.

Perhaps the most frequently used generic monad function is m-lift. It converts a function of n standard value arguments into a function of n monadic expressions that returns a monadic expression. The new function contains implicit m-bind and m-result calls. As a simple example, take

(def nil-respecting-addition
  (with-monad maybe-m
    (m-lift 2 +)))

This is a function that returns the sum of two arguments, just like + does, except that it automatically returns nil when either of its arguments is nil. Note that m-lift needs to know the number of arguments that the function has, as there is no way to obtain this information by inspecting the function itself.

To illustrate how m-lift works, I will show you an equivalent definition in terms of domonad:

(defn nil-respecting-addition
  [x y]
  (domonad maybe-m
    [a x
     b y]
    (+ a b)))

This shows that m-lift implies one call to m-result and one m-bind call per argument. The same definition using the sequence monad would yield a function that returns a sequence of all possible sums of pairs from the two input sequences.

Exercice: The following function is equivalent to a well-known built-in Clojure function. Which one?

(with-monad sequence-m
  (defn mystery
    [f xs]
    ( (m-lift 1 f) xs )))

Another popular monad operation is m-seq. It takes a sequence of monadic expressions, and returns a sequence of their result values. In terms of domonad, the expression (m-seq [a b c]) becomes

(domonad
  [x a
   y b
   z c]
  '(x y z))

Here is an example of how you might want to use it:

(with-monad sequence-m
   (defn ntuples [n xs]
      (m-seq (replicate n xs))))

Try it out for yourself!

The final monad operation I want to mention is m-chain. It takes a list of one-argument computations, and chains them together by calling each element of this list with the result of the preceding one. For example, (m-chain [a b c]) is equivalent to

(fn [arg]
  (domonad
    [x (a arg)
     y (b x)
     z (c y)]
    z))

A usage example is the traversal of hierarchies. The Clojure function parents yields the parents of a given class or type in the hierarchy used for multimethod dispatch. When given a Java class, it returns its base classes. The following function builds on parents to find the n-th generation ascendants of a class:

(with-monad sequence-m
  (defn n-th-generation
    [n cls]
    ( (m-chain (replicate n parents)) cls )))

(n-th-generation 0 (class []))
(n-th-generation 1 (class []))
(n-th-generation 2 (class []))

You may notice that some classes can occur more than once in the result, because they are the base class of more than one class in the generation below. In fact, we ought to use sets instead of sequences for representing the ascendants at each generation. Well… that’s easy. Just replace sequence-m by set-m and run it again!

In part 3, I will come back to the :when clause in for loops, and show how it is implemented and generalized in terms of monads. I will also explain another monad or two. Stay tuned!

March 5, 2009

A monad tutorial for Clojure programmers (part 1)

Filed under: Libraries — khinsen @ 6:15 pm

Monads in functional programming are most often associated with the Haskell language, where they play a central role in I/O and have found numerous other uses. Most introductions to monads are currently written for Haskell programmers. However, monads can be used with any functional language, even languages quite different from Haskell. Here I want to explain monads in the context of Clojure, a modern Lisp dialect with strong support for functional programming. A monad implementation for Clojure is available in the library clojure.algo.monads. Before trying out the examples given in this tutorial, type (use 'clojure.algo.monads) into your Clojure REPL. You also have to install the monad library, of course, which you can do by hand, or using build tools such as leiningen.

Monads are about composing computational steps into a bigger multi-step computation. Let’s start with the simplest monad, known as the identity monad in the Haskell world. It’s actually built into the Clojure language, and you have certainly used it: it’s the let form.

Consider the following piece of code:

(let [a  1
      b  (inc a)]
  (* a b))

This can be seen as a three-step calculation:

  1. Compute 1 (a constant), and call the result a.
  2. Compute (inc a), and call the result b.
  3. Compute (* a b), which is the result of the multi-step computation.

Each step has access to the results of all previous steps through the symbols to which their results have been bound.

Now suppose that Clojure didn’t have a let form. Could you still compose computations by binding intermediate results to symbols? The answer is yes, using functions. The following expression is in fact equivalent to the previous one:

( (fn [a]  ( (fn [b] (* a b)) (inc a) ) )  1 )

The outermost level defines an anonymous function of a and calls with with the argument 1 – this is how we bind 1 to the symbol a. Inside the function of a, the same construct is used once more: the body of (fn [a] ...) is a function of b called with argument (inc a). If you don’t believe that this somewhat convoluted expression is equivalent to the original let form, just paste both into Clojure!

Of course the functional equivalent of the let form is not something you would want to work with. The computational steps appear in reverse order, and the whole construct is nearly unreadable even for this very small example. But we can clean it up and put the steps in the right order with a small helper function, bind. We will call it m-bind (for monadic bind) right away, because that’s the name it has in Clojure’s monad library. First, its definition:

(defn m-bind [value function]
  (function value))

As you can see, it does almost nothing, but it permits to write a value before the function that is applied to it. Using m-bind, we can write our example as

(m-bind 1        (fn [a]
(m-bind (inc a)  (fn [b]
        (* a b)))))

That’s still not as nice as the let form, but it comes a lot closer. In fact, all it takes to convert a let form into a chain of computations linked by m-bind is a little macro. This macro is called domonad, and it permits us to write our example as

(domonad identity-m
  [a  1
   b  (inc a)]
  (* a b))

This looks exactly like our original let form. Running macroexpand-1 on it yields

(clojure.algo.monads/with-monad identity-m
  (m-bind 1 (fn [a] (m-bind (inc a) (fn [b] (m-result (* a b)))))))

This is the expression you have seen above, wrapped in a (with-monad identity-m ...) block (to tell Clojure that you want to evaluate it in the identity monad) and with an additional call to m-result that I will explain later. For the identity monad, m-result is just identity – hence its name.

As you might guess from all this, monads are generalizations of the let form that replace the simple m-bind function shown above by something more complex. Each monad is defined by an implementation of m-bind and an associated implementation of m-result. A with-monad block simply binds (using a let form!) these implementations to the names m-bind and m-result, so that you can use a single syntax for composing computations in any monad. Most frequently, you will use the domonad macro for this.

As our second example, we will look at another very simple monad, but one that adds something useful that you don’t get in a let form. Suppose your computations can fail in some way, and signal failure by producing nil as a result. Let’s take our example expression again and wrap it into a function:

(defn f [x]
  (let [a  x
        b  (inc a)]
    (* a b)))

In the new setting of possibly-failing computations, you want this to return nil when x is nil, or when (inc a) yields nil. (Of course (inc a) will never yield nil, but that’s the nature of examples…) Anyway, the idea is that whenever a computational step yields nil, the final result of the computation is nil, and the remaining steps are never executed. All it takes to get this behaviour is a small change:

(defn f [x]
  (domonad maybe-m
    [a  x
     b  (inc a)]
    (* a b)))

The maybe monad represents computations whose result is maybe a valid value, but maybe nil. Its m-result function is still identity, so we don’t have to discuss m-result yet (be patient, we will get there in the second part of this tutorial). All the magic is in the m-bind function:

(defn m-bind [value function]
  (if (nil? value)
      nil
      (function value)))

If its input value is non-nil, it calls the supplied function, just as in the identity monad. Recall that this function represents the rest of the computation, i.e. all following steps. If the value is nil, then m-bind returns nil and the rest of the computation is never called. You can thus call (f 1), yielding 2 as before, but also (f nil) yielding nil, without having to add nil-detecting code after every step of your computation, because m-bind does it behind the scenes.

In part 2, I will introduce some more monads, and look at some generic functions that can be used in any monad to aid in composing computations.

March 4, 2009

dorun, doseq, doall

Filed under: General — cosmin @ 4:34 am

It’s about time that I started writing some posts on this blog. I’ll start with something small, by talking about the difference between dorun, doseq and doall and how to easily remember what each one of them does. All of them are supposed to force evaluation of lazy sequences. At least to me it was not obvious from the name of these functions and I had to constantly go back to the docstrings at first.

doall

doall forces the evaluation of the lazy sequence and it retains the head, causing the entire seq to live in memory. Useful when you want to immediately force evaluation of something like map. I use the “all” part of doall to help me remember that it keeps all the items of the seq in memory.

dorun

Use dorun when you just want the side effects of computing the lazy sequence, but you don’t care about the items in the sequence itself. But be careful when you see yourself using (dorun (map ….. )), you should probably use doseq instead. I use the “run” part of dorun to help me remember that it only runs over the seq for side effects, without keeping anything.

doseq

To me doseq has more in common with for than with doall or dorun. Since in Clojure for is used for lazy list-comprehension, doseq fulfills the role of something like “for … in …” or “foreach” from other languages. It takes the same arguments that for does, but it runs immediately and it doesn’t collect the results. I really feel that doseq needs a better name so I don’t have a good way to remember what it does just by looking at its name.


The Shocking Blue Green Theme Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.