Latest blog posts

Feb 15 2010

Monads: redux

The discussion from Welcome to the Machine on Hacker News raised some interesting points. There is one in particular I would like to focus on:

“Personally, I don’t see why every language is trying to copy Haskell’s monads. A monad is not some deeply important concept, it’s just an abstraction that happened to be very useful in the context of Haskell’s type system. Without Haskell’s type system, it is not quite as useful, and it’s possible that other abstractions would be better.” — Jonathan Rockway

There are a few questions in this quote I would like to consider:

  • Why are programmers everywhere getting excited about monads, and trying to reimplement them in their language(s) of choice?
  • Can monads be useful outside the context of Haskell’s type system?
  • Are monads the most appropriate concept in Clojure for what we have been examining?

There is one question I would not like to consider: “Can monads exist in a dynamically typed language?”. This argument was thrashed in the above discussion thread.

Firstly then, why copy monads? There has been a lot of buzz about them as Haskell has become more popular. Underneath all the hype and confusion surrounding the concept is a simple concept: Function composition of which monads are a particular form with a set of laws. Haskell’s syntax and type system is particularly well suited to using monads to express abstraction.

New ideas spread through computing by cross pollination. If we weren’t experimenting with trying to implement another languages interesting features in our own language of choice, the growth and development would be much slower. Some anecdotes (none sourced):

  • Python took list comprehensions straight out of Haskell, but did so without specifically monadic underpinnings. Since then generator comprehensions and dictionary comprehensions have been added to the language and are important tools in the Python programmers toolbox.
  • Microsoft introduced LINQ into .Net; This is particularly relevant as it is a transplanting of monads with new syntax support. LINQ to databases is the least interesting application. LINQ to objects is a sequence monad and provides a rich comprehensions notation, and Rx is roughly the continuation monad and is intended to facilitate reactive programming.
  • Lexical closures - bread and butter for functional programming, and now central to most modern programming languages - came about via cross pollination from Algol 60 (and Pascal?) to Lisp. When this was transported to Lisp it was discovered to be immensely powerful. Emacs Lisp is now the only remaining lisp that does not support them.1

I’m sure everyone could produce many more examples.

Wholesale aggregation of features doesn’t really help. We need to evaluate if the concept being experimented with is worth inclusion. As Rockway says above, it is possible that there is a better abstraction that suits Clojure better than monads. This brings us to the second and third questions raised.

Can monads be useful outside of Haskell’s type system? In the context of Clojure, I would say that yes they can. Are they necessarily optimal? In a lot of cases no; Clojure provides reference types for managing state and because the language isn’t lazy we always have sequenced operations anyway. That is two reasons you might use a monadic construction in Haskell.

Whats left for us is the value of monads for providing abstractions over expression. We could see this with the backtracking and nondeterministic monads from Ghosts in the Machine. One of the key features of Clojure’s monads library is the Monad Comprehension form known as domonad. It allows us to implement these useful forms without having to step straight to writing macros. The downside is the need to be explicit about the monad we are using, and the onus on the user to understand what is going on.

In the last post I claimed that using monads to construct a parser combinator was an interesting and expressive model. What I want to look at now is what that monad provides for us, and what other features of Clojure could be brought to bear against this problem. Now for a caveat; I am still a novice with Clojure, so this section will be left open2.

Firstly, the biggest features we get from the parser monad:

  • The state of the input stream (the remainder) flows naturally through the parsers. It is also pure-functional; there is no mutable state. This is a big benefit for testing and understanding.
  • Backtracking is provided for us with no extra mechanical considerations: The call stack holds our states for us, and because its pure-functional theres no concern about a parser having messed with the stack.
  • We have parser comprehension syntax complete with guards.
  • Once we have written our primitive parsers of choice (in my case that was just get-one,eof, and ‘choice’) we never had to deal with the underlying abstraction again.

How would we reproduce these requirements (tracking state, tracking branch points at the state at the time, a convenient notation, and abstracting users away from the mechanics)?

The first and second points are closely tied together, lets consider the second (the backtracking stack) first. As the parser walks the input stream, it is going to have to keep modifying the top most element on the stack. Each time we encounter a choice, we need to create a new top of stack to remember the old choice and provide a way to continue from where we left off with the old value and state of the input.

We need a mechanism to maintain this stack and allow the primitives to mutate it. Clojure’s provides 4 core reference types to maintain state: Vars, Refs, Agents, Atoms. The later three are specifically concerned with concurrent activity. Vars are intended to allow per-thread local rebinding. This sounds most like what we want. We can use a binding form inside run-parser to create a nested binding, and then our primitive parsing operations can use set! to update the state. The use of binding also means we can safely call a second (completely distinct) parser inside the first without fear of it destroying our backtrack stack. This is similar to using a thread local variable in another language.

That covers points one and most of two, but at the cost of loosing our pure-functional expression. We have however gained primitives that do not need to expose a monadic interface. From a complexity perspective this appears to be a mixed bag.

So we can now manage the state of the parser stack, but we don’t have a mechanism to signal failure. The most obvious choice here would be to throw an exception. Some developers are not keen to use exceptions to manage flow control, but I cannot think of a replacement.

Parser comprehensions? well, we can now just use straight functions and let forms. We don’t have a guard notation any longer, but we can plug that gap with a ‘fail’ primitive, potentially passing additional information into it. If we need a more sophisticated form, we could always write a macro on top of these building blocks.

Lastly, we should still be able to write parser combinators in terms of a small set of abstractions, so both approaches appear to are equal on this count.

This brings us to the last question raised at the start; are monads the most appropriate tool for job in Clojure? This is hard to answer, because monads are such an abstract concept. As I noted above, a number of the reasons you would use monads in Haskell are redundant in Clojure, however, there are still situations that could warrant their usage. Indeed, the parser combinators case we examined is a mixed bag for both solutions.

Using monads lets us have a pure functional solution, at the cost of some transparency, especially for developers less experienced in monadic logic, while a ref type based approach uses some inelegant tactics to reproduce the system at the cost of pure-functionality.

So, monads do have a place, but that place is more restricted in Clojure than in Haskell. You could comfortably get by without knowing about them, but there are situations where they will help. This sort of experimentation is a vital part of the growth of languages, and of developers individual skills.

See Also:

Footnotes

  1. I read this story very recently but can no longer find the source. If somebody knows what it is I will update this to point to it. In the mean time, treat it as highly apocryphal.
  2. More experienced opinions and alternatives are greatly valued here.
Feb 12 2010

Ghosts in the Machine

This is the second (and final) part of my examination of the State monad and its variations. If you are unfamiliar with the basic concepts surrounding the State monad, you may wish to read the first part before continuing.

Backtracking State

One of the features of the State monad worth looking at is how it implements a simple interpreter. Our current interpreter lets us write any sort of procedural code we needed, though it might get rather unwieldy (only one register and one memory location). While interesting, its not especially useful.

Recall my claim that State is the basis of more interesting monads. We are going to look at a modification to the code from state-m that lets us backtrack if the computation fails to the last choice point.

The paragraph above introduces the three new features we need to provide:

  • A way to define choice points
  • A way to define computation failure
  • A mechanism to handle backtracking.

The two former points happily coincide with the interface for monad plus monads. Specifically the function m-zero will represent our failure mode, and m-plus will represent choice points. The last case (backtracking) will be implemented in m-bind and m-plus.

Before we go any further, here is an implementation I have cooked up based on the previously defined state-m1 monad.

(use 'clojure.contrib.monads)

(defmonad backtrack-state
    [m-result (fn [value]
                  (fn [state]
                      [value state]))

     m-bind (fn [computation func]
                (fn [state]
                    (when-let [[value new-state] (computation state)]
                              ((func value) new-state))))

     m-zero (fn [new-state] nil)

     m-plus (fn [left right]
                (fn [state] 
                    (if-let [result (left state)] 
                            result 
                            (right state))))])

Note that m-plus is a function that returns a function with the same type as m-bind and m-result. However, m-zero is strictly a value, which happens to be a function that always returns nil.

m-zero is our first hint at how this backtrack-state is constructed. A failure is nil, a successful computation returns the familiar [value state] pair from the regular state-m.

A small change has been made to m-bind. In particular, where state-m1 would just use a let to destructure the result of (computation state), backtrack-state uses when-let. This form fuses when and let so that when the lets binding-form’s source is also the test for when. If the test returns a truthy value (in our case not nil) then the body of the form is evaluated and returned. Otherwise nil is returned.

An alternative formulation is presented here for clarity

(when (computation state) 
    (let [[value new-state] (computation state)]
         ((func value) new-state)))

This means that if ‘computation’ fails the result will be failure without having to evaluate ‘func’.

The remaining logic is in m-plus. This function takes two arguments, both potential computations to perform, and returns a state consuming function. if-let is a cousin to when-let, and provides a failure branch rather than just returning nil.

Lastly, the implementations of get-state and put-state are identical to the versions from state-m1

To illustrate the expressive power of this new monad we have written, we are going to look at a small library built on top of it. There are two parts to this, first is a basic set of parser tools, and then there is the specific parser we are going to write. At the end we will have a little parser that will take a string representing a number and return a pair of either :int or :float depending if there is a decimal component. If anything else is found, it will fail returning only nil. So, the parser library:

(with-monad backtrack-state
    (defn run-parser
        "run-parser takes a top level parser and a string or seq'able
         to run the parser on"
        [parser input]
        (parser (lazy-seq input)))

    ;; primatives
    (defn get-one []
        "Gets the next item from the input and returns it"
        (domonad [input (get-state)
                  _ (put-state (rest input))]
            (first input)))

    (def eof
        (domonad [remaining (get-state)
                  :when (= (count remaining) 0)]
            nil))

    ;; simple parsers
    ;;
    ;; These parser's are built on top of the primatives above
    (defn one-satisfying [p]
        "This is the most basic matching parser. It tests the next
         item in the sequence against the predicate provided. If 
         true, then it is returned, otherwise fails."
        (domonad [one (get-one)
                  :when (p one)]
              one))

    (defn one-of [any-of]
        "Matches any one item in the provided collection or string"
        (one-satisfying (set any-of)))

    (defn not-one-of [none-of]
        "Matches any one item not in the provided collection or string"
        (let [none-of (set none-of)]
        (one-satisfying #(not (none-of %)))))

    ;; combinators    
    ;;
    ;; These parsers combine other parsers into new parsers
    (defn choice [& parsers]
        "Choice takes one or more parsers (in order) and returns a new 
         parser that tries each one in turn until one matches. If 
         all fail, then choice fails"
        (reduce m-plus parsers))

    (defn many [p]
        "Many matches the same parser 0 or more times until it it fails, 
         then it returns a sequence of the match results"
        (choice (domonad [r p
                          rs (many p)]
                      (cons r rs))
                 (m-result '())))

    (defn many1 [p]
        "Many1 is like many, but must match at least 1 item"
        (domonad [r p
                  rs (many p)]
            (cons r rs)))

    (defn optional 
        "This parser matches 0 or 1 of some parser. Optionally may take
         a default result"
        ([p] (optional p nil))
        ([p default] (choice p (m-result default)))))

If you have never used a parser combinator library before, this might seem a bit strange. Possibly the most surprising thing initially is that there is no lexical analysis step. Next, you have infinite lookahead. If parsing fails, we just fail back too the last m-plus point. Lastly, we build parsers by combining simpler parsers programmatically. The toolkit provides the simplest parsers and the basic parser combinators (parsers that are built by combining other parsers).

To put two parsers into sequence, we can just use m-bind. This means we can leverage monad comprehensions (i.e. the domonad form) to specify that one parser.

Looking at the functions in this little library you could come to the conclusion that its effectively a regular expression engine written verbosely. Certainly we have all the same primitives (one-of, many, many1, optional). The difference is that we have the full power of the host language (in this case Clojure) to call one. We’ll come back to this later with a small hypothetical parser.

This library also has one very nice feature: it is completely data agnostic, nowhere in it does it care if its processing a string of characters, a vector of ints or anything else. As long as it can be converted into a sequence, and the items in that sequence are comparable it’s good.

One last note about this particular implementation. Besides being tied to our backtracking-state monad it also suffers from a very flawed implementation of many. In particular, our implementation is elegant but relies on recursion. Remember that domonad will transform our code into a heavily nested set of function calls, and you can see that this fundamental combinator would quickly cause our whole parser to blow stack.

So with this basic set of tools in hand, lets look at the specific parser implementation:

(with-monad backtrack-state
    (def parse-digit (one-of "0123456789"))
    (def parse-digits (many1 parse-digit))
    (def parse-sign (one-of "+-"))
    (def parse-dot (one-of "."))

    (def parse-integer 
        (domonad [digits parse-digits]
            [:int digits]))

    (def parse-float
        (domonad [whole-digits parse-digits
                  _ parse-dot
                  decimal-digits parse-digits]
            [:float (concat whole-digits "." decimal-digits)]))

    (def parse-number 
        (domonad [sign (optional parse-sign "+")
                  [type digits] (choice (domonad [int parse-integer
                                                  _ eof]
                                              int) 
                                        (domonad [float parse-float
                                                  _ eof]
                                            float))]
             [type (apply str (cons sign digits))])))

This parser is very simple. It only has 2 backtracking points; the optional for parse-sign and the choice for digits. Both of these backtracking points only use m-plus indirectly, and you might have noticed that get-state and put-state are never needed outside the primitive get-one.

To run this parser, we’ll pass it and an input into run-parser:

(map #(run-parser parse-number %) ["123" 
                                   "" 
                                   "123.123" 
                                   "0" 
                                   "0.0"
                                   "-1"
                                   "1 2"])
;; => ([[:int "+123"] ()] nil [[:float "+123.123"] ()] [[:int "+0"] ()] [[:float "+0.0"] ()] [[:int "-1"] ()] nil)

You can see that each string we have parsed has returned a pair or nil. nil indicates a failure (no match), the pair is the complete parsed result containing the result of the parser and the remaining tokens to parse. Because we specified an eof in our parse-number parser we never have any remaining input.

Just as an illustration of how this style of parser is so expressive, here is a hypothetical that parses an xml element:

(with-monad backtracking-state
    (defn open-tag []
        (domonad [_ (one-of "<")
                  name (elem-name) 
                  attrs (attributes)
                  _ (one-of ">")]
            [name attrs]))

    (defn xml-element 
        []
        (domonad 
            [[name attrs] (open-tag)
             children (many xml-node)
             _ (close-tag name)]
            [:element name attrs children])))

Obviously, this is a very simplified ideal of xml, but you can see how leveraging the host language allows us to provide recursive parsers (xml-node will eventually try xml-element again), and pass information through (e.g. name from open-tag is passed to close-tag).

Nondeterministic State

After backtrack-state the step to nondeterministic-state is very small. Conceptually, we want to evaluate the computation for ever possible choice we encounter. Once again we will use monad plus to define choice points and failure. Unlike backtrack-state we will need to change the type of data returned by the state machine from a single value (a pair or nil) to a collection of value-state pairs.

The choice of collection proves interesting. There are two obvious candidates: vector and set. The difference is small but significant. A vector will result in every result including any duplicates. This will be useful if you are searching for the total possible solutions. However if you only care for every unique result then the set makes more sense as it will reduce the total computation in the case of repetition. We will come back to this decision in the last section (Transformations).

Heres the code for a set based nondetermistic-state monad.

(use 'clojure.contrib.monads)
(use 'clojure.set)

(defmonad nondeterministic-state
    [m-result (fn [value]
                  (fn [state]
                      #{[value state]}))

     m-bind (fn [computation func]
                (fn [state]
                    (let [results (computation state)
                          result-sets (map (fn [[value new-state]] 
                                                ((func value) new-state))
                                            results)]
                        (apply union result-sets))))

     m-zero (fn [new-state] #{})

     m-plus (fn [left right]
                (fn [state] 
                    (union (left state) (right state))))])

(defn nd-get-state 
    [] 
    (fn [state] #{[state state]}))

(defn nd-put-state 
    [state] 
    (fn [_] #{[nil state]}))

The changes here are all fairly straight forward. Places we added logic for backtracking now find the union of sets, and m-zero returns a empty set rather than nil. The final change is that we have to use a new version of get-state and put-state that handles the set wrapper.

A simple example of this monad in action is the quadratic formula; square root fails for negative numbers, and returns both positive and negative values for any positive number. The follow implementation is a little rough but demonstrates the concept:

(defn sqrt [v]
    (with-monad nondeterministic-state
       (if (> v 0) 
           (m-plus (m-result (Math/sqrt v)) (m-result (* -1 (Math/sqrt v))))
           m-zero)))

(defn quadratic 
    [a b c]
    ((domonad nondeterministic-state
        [roots (sqrt (- (* b b) (* 4 a c)))]
        (/ (+ (- b) roots) (* 2 a))) nil))

Here it is in action with some sample inputs:

(quadratic 1 20 4)
; => #{[-0.20204102886728847 nil] [-19.79795897113271 nil]}
(quadratic 1 2 4)
; => #{}

Transformations

We have looked at three variations of the State concept. Recall that I mentioned there is a relationship between the simple monads: Identity, Maybe and Set. The type signatures for the Haskell equivalents make this particularly clear

newtype State s a = State { runState :: (s -> (a,s)) } 

newtype BTState s a = BTState { runBRState :: (s -> Maybe (a,s)) } 

newtype NDState s a = NDState { runNDState :: (s -> [(a,s)]) }
   -- Note the use of list/seq instead of set, but provides similar behaviour

Since we started with state-m1 as our base, it is fairly obvious that this is going to relate to the Identity monad. backtracking-state relates to the Maybe monad, and nondeterminstic-state relates to the Set monad, alternatively it is possible to implement a nondetermistic-state on top of a Sequence / List monad.

This idea that one monad can wrap another is interesting. Without going into too much detail, it is possible to write a function that takes a monad type as its argument (the inner monad), and wraps it up in another monad that has been written in terms of the standard monadic operations.

This idea is know as a monad transformer. The transformer is the function that transforms (or decorates) the inner monad. The Clojure monad library provides a macro for defining transforms called (unsurprisingly) monad-transformer. We can shortcut all the hard work above with a couple of one liners!

(def backtrack-m (state-t maybe-m)) ; you might also see this called parser-m

(def nondeterministic-m (state-t set-m))

You could also choose to use sequence-m in place of set-m for the nondeterministic-m. It is important to realise that the order of the wrapping makes a significant difference with regard to the semantics of the generated Monad.

The specific implementation details of creating a transformer are left to the reader to explore if they are interested. Jim Duey’s second monad’s tutorial covers transformers in more detail. Personally I think this is one area where Clojure’s monad support is superior to Haskell’s as we don’t have to appease such a strict type system. This also makes Haskell based Monad Transformer tutorials a lot more complex.

Wrapping up

We have now looked at three related monads in some detail, seen how they can be used to write some amazingly expressive code, and encountered the tools to make these sorts of operations much easier to wield.

The parser library provided here has an elegant interface but has a very naïve implementation. Recursion will cause problems with the implementation of many, and the astute reader will have noticed that the design causes it to hold onto the head of the input sequence. To convert it from a generic backtracking monad to a specialized parser monad is an interesting project well worth exploring. Another exercise would be implementing a non-determistic monad without a state component.

Finally, a big thanks to Matt and Steven for their help proof reading these posts.

Discuss this post on the Hacker News thread

Feb 10 2010

Welcome to the Machine

Today I’m going to dive into the deep end and take a look at the State monad1, with an implementation in Clojure. This will be done using Konrad Hinsen’s clojure.contrib.monads API, but I will be providing my own specific monad implementations for continuity. You should use the API versions of any of these monads in the real world however.

The first question to ask is “why use a State monad in Clojure; there is already great support for state management in the language”. My answer is “because the State Monad is the foundation of more interesting monads.” In particular we will be looking at Backtracking State and Nondeterministic State monads. You might use Backtracking to build a parser combinator library2. The Nondeterministic state allows you to find all the solutions that fit some problem. A simple example might be an implementation of the Quadratic Formula.

We’ll look at these monads in turn, and then wrap up with a quick high level look at the role Monad Transformers could play, and the relationships between these variations on State and some other monads you may have already encountered: Identity, Maybe and Set.

State

First thing to consider about the state monad is what it is. Ignore the more academic answers to that question, the state monad is a way of building a state machine. It does not hold some state in it, instead it is a series of functions which a state is threaded through. Haskell has a curious looking type for State

newtype State s a = State { runState :: (s -> (a,s)) }

State is a wrapper type that contains a single value. This value is a function from type s to a pair of type a and type s. The curious thing about this definition is it uses the record syntax in Haskell to call the value runState. It does this so that you can unpack the state and apply it to the initial state in one step. Eg:

(runState myStateMachine) initialState  --  parens are for clarity

In Clojure land, we are going to not concern ourselves with a concrete wrapping type. Instead our monad will just return a function. The last thing to think about is what s and a represent. s is the state, and a is the value that that function returns. In our clojure code this will look like a function of one argument (the initial state) that returns a vector of two items: the value and the new state.

Before we go any further, lets have a quick look at the code for this state-m monad. I’ve called it state-m1 to avoid clashing with the state-m in the monad library.

(use 'clojure.contrib.monads)

(defmonad state-m1 
    [m-result (fn [value]
                  (fn [state]
                      [value state]))

     m-bind (fn [computation func]
                (fn [state]
                    (let [[value new-state] (computation state)]
                         ((func value) new-state))))])

While all the interesting behavior happens inside m-bind, m-result is indicative of the nature of the monad. Haskell calls this function return which sufficiently confuses many people, and I like to call it introduce because it introduces a new value into the computation. As is mentioned above, the State is a function from initial state to a value and new state, and as you can see m-result takes a value and returns a function. In this function, the value is constant, and the state is whatever state that gets passed through it.

m-bind provides the guts of the monad. And, because it does a whole lot of function wrangling, it can be a little difficult to wrap your brain around at first. Because this is key to understanding the rest of the monad, and the derivative monads, we will examine this one slowly.

First thing to notice is that like m-result, m-bind returns a new function that takes a state and returns a value-state pair. Second thing is the names of the arguments to m-bind. I have called them computation and func. computation is the existing state-machine and func is the function to use as the next step in the state-machine. In the same way that a linked list is a head and tail, and cons stitches them together, m-bind stitches together func and computation, the big difference is the facing. computation is the many unit, and func is the singular unit3.

Lets look at a very simple (and contrived) example. We’ll look at how you set would write some code to use it, and then have a look at what that transforms into. This is going to introduce a value into the computation, increment it, and return that new value, all the while ignoring the state that the caller has specified.

 (def my-state-machine (domonad state-m1 
      [my-val (m-result 1)
       my-val2 (m-result (inc my-val))]
       my-val2)) 

 (my-state-machine "state") ;; -> [2 "state"]

If this looks like a strange way to write a let form to you, you would be right. We currently have no easy way to deal with the state in our state machine, we can only thread the value through. Before we do that though, lets unwind that expression.

First up is (m-result 1). This creates a function as we can see from the definition of state-m1. Specifically it produces

(fn [state] [1 state])

This becomes our computation for the first bind4:

(m-bind (fn [state] [1 state]) 
        (fn [my-val] (m-result (inc my-val))))

Lets do a straight forward reduction here to see what we get. I’ve copied the body of m-bind from above, and where it says computation I’m replacing it with (fn [state] [1 state]) and whenever it says func I’m replacing it with (fn [my-val] (m-result (inc my-val))):

(fn [state]
    (let [[value new-state] ((fn [state] [1 state]) state)]
         (((fn [my-val] (m-result (inc my-val))) value) new-state)))

Lastly we have a bind to get my-val2 out of the big computation. This is once again a fairly straight forward reduction, only with a larger computation.

(fn [state]
    (let [[value new-state] ((fn [state]
                                 (let [[value new-state] ((fn [state] [1 state]) state)]
                                      (((fn [my-val] (m-result (inc my-val))) value) 
                                       new-state))) state)]
         (((fn [my-val2] (m-result my-val2)) value) new-state)))

So thats the basic transformation from the domonad notation. You can see how the various expressions have been stitched into the state-machine. Next we’ll do another set of reductions so you can see how the state is threaded through the stages of the machine. As above the string “state” be passed through.

Reducing the state-machine

Note: If you are comfortable with how this reduces down, skip on to the next section

First the argument to the machine is replaced (see the end of the second last line):

(let [[value new-state] ((fn [state]
                             (let [[value new-state] ((fn [state] [1 state]) state)]
                                  (((fn [my-val] (m-result (inc my-val))) value) 
                                   new-state))) "state")]
     (((fn [my-val2] (m-result my-val2)) value) new-state))

Next that function in can be reduced down. This time the string “state” has moved to the end of the first line.

(let [[value new-state] (let [[value new-state] ((fn [state] [1 state]) "state")]
                            (((fn [my-val] (m-result (inc my-val))) value) new-state))]
     (((fn [my-val2] (m-result my-val2)) value) new-state))

And again. Note that the function producing the pair has been replaced with the specific pair.

(let [[value new-state] (let [[value new-state] [1 "state"]]
                            (((fn [my-val] (m-result (inc my-val))) value) new-state))]
     (((fn [my-val2] (m-result my-val2)) value) new-state))

At this point we can remove the top let, destructuring the pair we just created into value and new-state:

(let [[value new-state] (((fn [my-val] (m-result (inc my-val))) 1) "state")]
     (((fn [my-val2] (m-result my-val2)) value) new-state))

Now we can reduce down function. Recall that this function was introduced by the first m-bind.

(let [[value new-state] (((m-result (inc 1))) "state")]
     (((fn [my-val2] (m-result my-val2)) value) new-state))

This time we can increment 1 and replace the m-result with the result of that function.

(let [[value new-state] ((fn [state] [2 state]) "state")]
     (((fn [my-val2] (m-result my-val2)) value) new-state))

The reduction should be starting to look familiar. “state” will be used to reduce the result of that m-result.

(let [[value new-state] [2 "state"]]
     (((fn [my-val2] (m-result my-val2)) value) new-state)))

Once more destructuring out the let form

(((fn [my-val2] (m-result my-val2)) 2) "state")

Reduce the inter function

((m-result 2) "state")

Expand out m-result

((fn [state] [2 state]) "state")

And finally reduce that down.

[2 "state"]

That looks like a lot of work, but it is actually straight forward. Still, its not very useful if it just provides a complicated version of the let form.

Manipulating the state

The most obvious state managing functions will be two primitives get-state which returns the current value of the state, and put-state which updates the current state5. To get handle on whats going on at this stage, I like think of the value as something like a register in the state-machine, and state as the sole memory location.

(defn get-state [] 
    (fn [state] [state state]))

(defn put-state [new-state]
    (fn [_] [nil new-state]))

These functions follow the familiar form indicated by m-result. The return a function that takes an initial state and returns a pair of value and current state.

get-state returns a function that takes the state value and places it in the value ‘register’, and leaves it in the state as well. In contrast, put-state takes a new state as its argument and the returns a function that ignores the current state, obliterates the value ‘register’ and updates the state.

So how would you go about using these two functions? Here is another contrived example that increments the current state, and returns the original value:

((domonad state-m1
    [v (get-state)
     _ (put-state (inc v))]
    v) 1) ;; -> [1 2]

I’ll leave reductions of this to the more eager reader.

Wrapping up

So that’s the basic State monad. It’s likely you won’t use this very often (ever?) in Clojure, but understanding it is very useful.

In the second (and final) part we’ll take a look at a couple of variations on this concept, including looking at some small example programs that make use of them.

Discuss this on the Hacker News thread.

Footnotes

  1. If you are unfamiliar with monads I would suggest you look else where. The api documentation provides links to a set of tutorials that are a good resource for Clojure programmers. You might also find my post Functions of functions useful.
  2. Parser Combinators are a way of describing a recursive decent parser using combinations of functions. These parsers can trivially have infinite lookahead, and the full expressive power of the host language. The canonical example of this idea is Parsec in Haskell, but the concept has been ported to many languages. In languages other than Haskell, they are often implemented using tricks other than monads, but Parsec is still the most elegant example.
  3. This is actually a simplification. In reality it might could be considered closer to two trees being joined as the leaves of a new tree.
  4. I am assuming you understand how bind is rewritten into nested function application from its domonad form.
  5. Once you are comfortable with how this simplistic implementation works, I would urge you to explore the code in clojure.contrib.monads.clj as it provides a much more sophisticated API, and uses some nice tricks. In contrast I have chosen to implement the canonical get and put.
Feb 08 2010

A couple of lists

From Python to Clojure.

In the last post I talked about factors that have caused myself and others to look around for languages to move on to from Python. I noted that a number of languages that expat pythonistas are looking at are more recent entries in the Functional Programming space. After dabbling in a number of languages over the last two years I have settled on Clojure. This post examines the tradeoffs from my perspective.

When I first came to Python it was around 2002. With a background in Java from university Python provided an appealing language to get things done. As a quick summary:

  • The syntax is clean and clear, including strong support for iteration (something that was “in the future” for Java at the time). Generator comprehensions were in the future meta-package at the time I believe.
  • Dynamic exploratory development with an excellent REPL is easy.
  • Access to foreign code from C-land has always been good1.
  • Great built in collections and literal support for the core ones. Lists, dictionaries, tuples, sets are all out of the box.
  • Simple and expressive Object Orientation.
  • Great range of libraries. Some particular worthy ones include Twisted, Django, WSGI, SciPy.
  • Comprehensive namespace and packaging tools.
  • Cross platform.

The big obvious tradeoff was speed but, as has been noted many times by many people, this isn’t a huge impediment for a large class of programs. Not so obvious is the GIL and the problems it brings to multi-threaded programs but I don’t want to go into that debate here.

Another problem that comes to the surface after extended use is packaging third party library code. Tools like virtualenv and pip etc have helped a lot in recent years, but its certainly not Python’s strength.

I’ve had the chance to work on some really cool projects with Python. I built a skinnable, scriptable media player with webservice integration for my internship, extracted a nice little parser combinator library from this site with some friends, I worked on a Django based financial application full time and a many more small projects.

Any language I move to has to feel as expressive as the experience I get with Python (sans learning curve difficulty). This brings us to Clojure.

I’ve been following Clojure since mid 2008, dabbling in it and writing little toy applications. The functional style has been appealing to me more and more. So what features does Clojure bring to the table for me?

  • It is a lisp, so the syntax is nearly nonexistant. However, it has more literals for data and these are used in the special forms. Clojure has (to a new-lisper) much nicer special forms, the obvious example is let compared to Common Lisp2.
  • Namespaces and modules support is solid. The differing rules for Clojure imports and Java imports tripped me up at first, but makes sense.
  • Dynamic exploratory development with the REPL. The REPL is a bit more raw than Python’s but is improving dramatically.
  • As mentioned above, there is a good set of literals for data. The built in data-structures are really good. Lists, vectors, maps (dictionaries), sorted maps, sets, sorted sets. This is an area Clojure really shines; not only are there all the basic collections I want, they are super fast and persistent (immutable), which sets things up well for concurrent operations.
  • Functional Programming is front and center, but supports mutability and state clearly.
  • Support for Java and Objects is solid. The inter-op / foreign function interface to Java-land is a core feature of Clojure.
  • “Clojure has objects but isn’t oriented around them.” — Chris Houser.
  • Cross Platform
  • Builds on Java’s code distribution tools like jar files, and Maven repos with Leiningen.
  • Fast. Type hints allow you to avoid reflection in many cases, and it compiles to the JVM.

One obvious lack for Clojure is (native) libraries that are as comprehensive as some of the ones for Python. There isn’t a web framework that competes with Django in terms of feature set and breadth for example. The language is very young (just over 2 years) and it is developing rapidly, but you might still find yourself building (or wrapping java) what you could have got from the toolbox in Python.

Secondly, if Object Orientation is key to how you design code, you will be out of luck. Same goes for JVM: If you have no love for the JVM platform, Clojure won’t be the right choice for you.

There is a lot of overlap between the two lists. Neither list covers all the great things about either language, just the things that spring to mind about why I like each.

So what makes Clojure more appealing than other Functional (or Hybrid OO/FP) languages? One key differentiator is that as a pragmatically designed language, IO and state considerations are clearly part of the plan. Not only this, the role of state, identity and time with regard to concurrency has been considered throughout the language’s and core library’s design.

Unlike Python (and other contemporaries like Java), Clojure does not provide mutability or identity to all data or variables. Instead, data is immutable, and the core data-structures are designed with that in mind. Secondly explicit reference types are provided. The programmer is expected to write core logic in a pure functionally mode where possible, and then use the reference types to maintain identity where needed. This will be familiar to anybody who has seen the buzz around functional programming and concurrency. Unlike in the C family, where pointers merely address memory, each reference type provides additional semantics. These semantics allow Clojure to provide managed statefulness; this is analogous to managed memory. A lot has been written about Clojure’s concurrency features, and by smarter people than me, so I won’t say any more.

One consideration with the current state of Clojure is that the planned 1.2 release is bringing two new constructs: Types and Protocols. These correspond roughly to Classes and Interfaces in Java. The current release (1.1) provides a Structs feature that uses dynamic maps as types, but this feature is due to be deprecated with 1.2. This places new users in an awkward position, but is a necessary change and will only be good in the long run.

The features that made Python a great choice in 2002 are no longer just the domain of so called ‘Scripting’ languages. Switching to Clojure does have trade-offs but it feels like the right choice for me.

Note: Discussion on the Hacker News thread.

Postscript

“Show Us The Code!” I’m not going to for this post. Snippets could be manufactured in situations that show each language as ‘better’. If you would like to see a small piece of Clojure written by a relative beginner, check out Caponia. This is an ultra light weight, in memory, full text index library that Matt and I designed during lunch and he implemented over the following day.

In contrast to this rather fluffy post, the next two will be looking at state and evaluation semantics in Clojure, chock full of code snippets. Update: The first half is now up.

See also

  1. hga on Hacker News provides a link dump of Clojure material. A great place to get started.

Footnotes

  1. These days its excellent with the ctypes library
  2. No doubt Common Lisp has good reasons for how it does things, but from the outside its opaque and frankly not as nice as Clojure. Clearly a subjective judgement, but I’m allowed to make those when I’m evaluating a language for my own use.
Feb 05 2010

On iteration

A Python programmer discovering the magic of itertools is three months from looking for a new language that better supports the functional style.

There is an observable trend in Python programmers that results in a reasonable section of them moving to functional programming languages. This trend is encouraged by the Python language, and has a couple of temporal considerations.

Firstly the language. Python has strong support for describing operations over aggregates. Most programmers coming to Python are coming from other procedural and OO languages, and these languages at best may support a for each style loop1. The iterations of understanding (and understanding of iterations) follow a familiar path:

The new Python programmer will begin by writing programs that use the familiar for loop to process collections. At some point the syntax for List Comprehensions will be discovered. He will begin to write more and more code in this form. Following List Comprehensions are Generator Comprehensions, and perhaps Generator functions and the yield keyword.

Eventually he will stumble across itertools. This module becomes many Python programmers’ favorite standard library component. This is the beginning of the end for his interest in Python. Why? Two key reasons:

  1. Python’s design and leadership prefer procedural and OO to the functional programming style. While the language can facilitate it, the library and syntax don’t support it naturally.
  2. Generators are a poor substitute for real lazy data structures. You can do a lot with them, but you hit the pain points fairly quickly.

Secondly the temporal considerations. Python is currently going through a major version change. This fixes many warts and problems in the language, but requires projects to be ported to the newer, cleaner Python 3.

Concurrently, Functional Programming has come to the fore in geekdom as an answer to difficulties with concurrency and expression. Two languages in particular are well positioned to be an easy jump for an experienced Python programmer: Clojure, and F#. Haskell is also a popular choice with more academically minded over F#. Scala may be preferred by those who still have a strong attachment to mixing OO and Functional styles.

F# provides the familiar whitespaced based syntax. It has syntax blocks for statement based-procedurally oriented programming, and a class syntax that feels very familiar to expat Pythonista.

Clojure is the other contender. As a modern lisp for the JVM it provides a familiar development enviroment. Clojure also provides a large palette of tools for concurrent programming — a particular pain point for Pythonistas3 — and is capable of running very fast.

Python’s ease of development has been matched by these more recent languages. They provide features that the experienced Pythonista wishes he had, and without sacrificing speed or expression. The choice will be dictated by the enviroment and personal choice, but there are clear choices beyond Python.

Note: Discussion on the Hacker News thread.

See also

Footnotes

  1. This is changing with C# providing LINQ (to objects in particular).
  2. Along with Smalltalk, recent C#s, Ruby, and other OO languages
  3. Via the Global Interpreter Lock, mutability as a default and a lack of primatives.
Oct 23 2009

Functions of functions

The following is some theoretical learning I have done about functions of functions in Haskell and F#. It uses haskells type and function notation but has a couple of F#s (perhaps actually ocaml?) names for functions because they are clearer for my purposes because they have clear directionality, and the flipped versions show some of the similar properties more clearly than the commonly used versions.

There are two main operations you can do with function values: Apply them, and compose them. One other operation referenced here is flip, which swaps the argument order of the function.

First up, the function application operator, with its haskell name and then the F# versions that i’m going to prefer:

1
2
3
4
5
$ :: (a -> b) -> a -> b
<| :: (a -> b) -> a -> b  -- Function application; 
<| = ($)
|> :: a -> (a -> b) -> b  -- Pipeline
|> = flip ($) 
The second common operator on functions is function composition; Again the haskell name followed by the F# names. The latter is not to be confused with haskell’s monad operator of the same name <<.
1
2
3
4
5
. :: (b -> c) -> (a -> b) -> (a -> c)
<< :: (b -> c) -> (a -> b) -> (a -> c)
<< = (.)
>> :: (a -> b) -> (b -> c) -> (a -> c) 
>> = flip (.)

In Haskell its not immediately obvious that monadic bind is related to function application; in this case apply a function to a value in a monadic context. With the flipped function application (aka pipeline) operator we can see clear similarities in the types:

1
2
3
4
|> :: a -> (a -> b) -> b 
>>= :: Monad m => m a -> (a -> m b) -> m b 
<| :: (a -> b) -> a -> b
=<< :: Monad m => (a -> m b) -> m a  -> m b 
Note that in both cases there is a function applied to a value, in the case of the bind operators that value is in a Monad type. The difference is that bind has a more specific type than plain application, in the form of a type that implements the monad interface. This provides richer semantics about the function application.

We know that there is a relationship between function application and function composition. This is particularly clear with pipeline and right facing compose. In this expression, g and h are both functions.

1
f val = val |> g |> h == f = g >> h
And given we know there is a relationship between bind and application, it can easily be supposed that there is a similar operation to composition specifically for monadic functions.

If we replace the three functions in the type of compose with monadic operations, we get an operator with a type such as:

1
2
3
4
>> :: (a -> b) -> (b -> c) -> (a -> c) 
>=> :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
<< :: (b -> c) -> (a -> b) -> (a -> c) 
<=< :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c)
Indeed this operator does exist and is known as Kleisli composition of monads.

Generalized functions of functions

A key feature that Monads bring is that they allow a single operator to generalize many different kinds of function applications. The types that implement the Monad typeclass in haskell each provide different contexts to manage how various functions are applied. The identity monad effectively is the function application operator dressed up with a more complex type.

Given there is a generalization for application, it seems likely that there would be a generalisation for composition too as we have already seen two general patterns. It turns out that there is, and in Haskell it is known as the Arrow typeclass. Of particular interest here, Arrow provides an operator:

1
>>> :: Arrow ar => ar b c -> ar c d -> ar b d 
An arrow type ‘ar a b’ represents a transformation from some type a to type b. For example:
1
2
3
4
a -> b -- becomes:
Arrow ar => ar a b
Monad m => a -> m b -- becomes:
(Arrow ar, Monad m) => ar a (m b)
This, the function application (>>) and Kleisli operators (>=>) can be represented in terms of Arrows as:
1
2
3
4
>> :: (a -> b) -> (b -> c) -> (a -> c) 
>>> :: Arrow ar => ar b c -> ar c d -> ar b d
>=> :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
>>> :: (Arrow ar, Monad m) => ar b (m c) -> ar c (m d) -> ar b (m d) 

What’s the point?

All this shows just shows a correspondence between monads, arrows and the primative operations of functions. In particular how those operations can be generalised when more specific types are involved.

Oct 16 2009

iPod Rejects

If you are like me, the amount of music you have on your computer is much greater than the amount of space on your iPod. Heres a tip on how to make managing your iPod selection significantly easier.

First up, you should have an playlist that the iPod is loaded from. My iPod uses “Andrew’s iPod Selection”. This is a normal static playlist that I manage by hand.

I have created a Smart Playlist that shows me all the tracks that are not on my iPod. I called it my iPod rejects.

Creating the playlist

To create this playlist, go to the File menu and click on New Smart Playlist.

The playlist editor will open. You want to make it match all the songs that are not in the ipod selection, and have a media type of music. Below you can see a screenshot that shows the setup.

When you first create a smart playlist there is only one rule. You will need to click the + button on the right to add a second. Make sure you have Live updating and match the following rules checked.

Set a Playlist rule to is not your iPod Selection playlist. Set the second — a Media Kind rule — to is and Music. This second rule is to make sure podcasts, videos, etc don’t get collected up with the music.

Managing the playlists

I have both my iPod Selection and iPod Rejects playlists set up to use the grid view. To change to Grid view, click on the View menu, and select Grid. I also set the View > Grid view option Albums selected, and View > Sort albums > By Artist selected. This allows me to easily skim the albums by artwork.

I populate my iPod Selection playlist by browsing the iPod Rejects playlist instead of the Music library. If you have enabled Live updating on the Smart playlist then tracks should disappear from the Rejects playlist immediately after you add them to the Selection playlist.

Oct 08 2009

Needless Facs

A pointless collection of factorial implementations in Clojure.

1
2
3
4
5
6
(defn fac1 
    "Basic recursive factorial"
    [n]
    (if (= n 1) 
        1 
        (* n (fac1 (dec n)))))

1
2
3
4
5
6
7
8
(defn fac2
    "Recursive factorial with loop/recur"
    [n]
    (loop [i n
           total 1]
        (if (= i 1)
            total
            (recur (- i 1) (* total i)))))

1
2
3
(defmulti fac3 identity)
(defmethod fac3 1 [_] 1)
(defmethod fac3 :default [n] (* n (fac3 (dec n))))

1
2
3
4
(defn fac4
    [n]
    "Factorial as an implicit hylomorphism" 
    (reduce * (range 1 (inc n))))

1
2
3
(defn fac5 
    [n]
    (apply * (take n (iterate inc 1))))

May 26 2009

Being about code

GitHub didn’t catch on because of Git. It may have helped, but it wasn’t the primary catalyst.

GitHub caught on because it’s about code. Sharing, finding, and contributing code.

Rubyforge and Sourceforge aren’t about code. They never were.

defunkt’s Gist

GitHub has been described as a social networking site. I think this is true, except that its the code that is social rather than the people. And it really works.

May 10 2009

Unmythic

I have discovered that a lot of the problems I have with many fantasy stories and games seems to stem from settings with very concrete backgrounds; All histories and science but no room for anything really mythic.

What do I actually mean by mythic? Stories, each one ages old, that explains something about the way things are in terms of heros and villians. These stories stand largely on their own, even if they are part of a greater mythic picture. And importantly myths conflict with each other. The best myths seem metaphorical, even when they contain some concrete truth.

This struck me while reading Open Grave, the D&D 4e undead book. D&D in particular has a very strong tradition of settings where the early history of the world is very well established. Given the sparseness of the D&D Points of Light implicit setting, the concreteness is unfortunate. Open Grave presents a very scientific explanation of undeath in the setting. The result is some very cool ideas, but none of the horror that I want to associate with undead.

In contrast, the Wheel of Time series of novels has done well at presenting both the explained histories that the people of the world knows, alongside the rumors and speculation of ordinary people of the world. Another example is Trail of Cthulhu’s chapters on the various Gods and Great Old Ones of the setting where multiple possibilities are presented for the keeper to consider.

Hellboy is another good example. The characters could realistically know about the myth and murky past of the world but it is generally shown rather than explained and is presented in a much more snapshot view. There are lots of snippets for the reader to see, but the bigger picture eludes them.

Apr 07 2009

The Haunting: Terms

A follow-up to the recap of The Haunting about some of the terms and ideas mentioned there, and a couple of others from such sources as The Sons of Kyros. These are all simple techniques that can be applied to most RPGs and help things tick over more easily.

Consider Yes and Say Yes, or Roll The Dice

I learnt about this from the Sons of Kyros. Any time a player asks to try something, the GM should consider saying yes if it wont upset things. Additionally, if you choose not to say “Yes”, then you consider rolling the dice to determine the outcome.

Let It Ride

This is an idea from the Burning Wheel family of games. The idea is that every time you pick up the dice it should matter. You only roll once for any test and that result holds until circumstances change.

For example, you only make one Library Use test for a particular search, not one per every 4 hours. The result holds until the situation changes. This might be finding a new set of clues. Eg; Doing a search of a newspaper morgue for references to “21 Sheafe St” might fail. Later in the hall of records you discover it was once owned by one Walter Corbitt Esq. Time to hit the library again.

It is important to realize this goes both way; The players must accept failure and the GM must accept the success.

Failure

Both Mouse Guard and Trail of Cthulhu spend a lot of effort making failure not derail the story. Failure should create a new situation to be resolved rather than just cutting short the course of action.

Core Clues

Following from that view of failure, Trail of Cthulhu makes it possible to find every clue that is required to solve the scenario. Characters still need to actively hunt for the clues, but no dice are rolled. Secondary clues are subject to the normal resolution.

The Enmity Clause

A specific case of Say Yes, or Roll The Dice taken from Burning Wheel’s Circles subsystem. In a situation where the player wants to find a character thus far unknown. In Burning Wheel, you test your circles attribute; A failed roll results in finding the character, but for some reason the new character has enmity toward the PCs.

In our game, after some chaos in the basement that resulted in one character being shot in the back and another in the arm, the investigators went in search of a back street doctor to perform the necessary surgeries for them under the table. The Lawyer suggested that from his firms defense practices he would know someone suitable. I rolled either Law or Credit Rating for him, but he failed.

They still found the doctor, but he was immediately suspicious of the wounds and blackmailed them to keep quiet about the incident. I planned to have the character create more trouble, but things didn’t quite work out that way.

Beliefs

Beliefs are a small but important part of how characters are defined in Burning Wheel. These are generally a one or two sentence statement that motivates the character. This might be a goal, a motivation, something immediate. The key thing is that it be something that pushes your character forward.

Of the Burning Wheel ‘BITs’ — Beliefs, Instincts and Traits — they are easiest to extract for use in other games even without the mechanical rewards built up around them.

See Also:

Apr 06 2009

The Haunting

I ran the classic Call of Cthulhu scenario The Haunting with my D&D group over a two nights as an interlude in our usual Age of Worms epic campaign. I’ll skip over the story details because the haunting has been covered so many times already.

Rules-wise, I used the core Call of Cthulhu BRP rule set, summarized to a page cheat sheet for the players. Additionally I tried to apply concepts from Trail of Cthulhu and the Burning Wheel family of games. Ideas like Let It Ride and Core Clues I explicitly used. The general flavor of how Trail and Burning Wheel treat dice rolling and failure held for a lot of the game. My favorite ruling was quietly using the Enmity Clause when the players were effectively circling up a back alley doctor to help with their (self inflicted) gunshot wounds.

What rocked

Beliefs; We played a pickup style game. I made 7 pre-gens for 5 players, only one character outline was provided for me. Each character was bare bones attributes plus skills, and a weapon of some description. Instead of writing complex back story for each character matt and I cooked up 2 or 3 beliefs per character and I handed those out when players selected characters. The players did a great job of taking the general shapes of characters and fleshing them out. There was a lot of great drama and conflict in the party that really built things up once they action reached the house.

In addition to the Beliefs, I managed to restrain myself at the start of the game and give the characters a few minutes to role-play introductions and flesh out their characters in game. Worked great, I’m sure I’ll use this technique again.

The prop newspapers and photos I spent ages making worked great. They should hopefully be going up on Yog-Sothoth once they have had a final edit.

What could have been better

There were a couple of scenes where I lost hold of the BW/ToC ideas and slipped back into more traditional style and framed scenes poorly. In particular the Chapel of Contemplation scenes were very weak and full of whiffs.

The end of the scenario felt quite anti-climactic; I don’t know whether this was because it came after the confusion and drama that started with upstairs bedroom and continued down in the basement, or because its just not a very exciting final scene after all that has gone before it.

Feb 26 2009

Comments, revisited

No comments‽” was a common theme in the response to monday’s post a better blog. I did not intend to imply that I don’t value the opinions and thoughts of my audience. Rather that comments are a poor medium for discussion.

Firstly, commenting generally has a low barrier to entry. It is easy to belt out a hurried, flippant, or poorly considered response. By moving the comments off the site the barrier to entry is higher; The responder is more likely to invest time in the reply.

Related to this, the reply has a stronger attachment to the author’s identity, and “…they’re forced to defend their ideas on their own turf…It forces a level of consideration that, without fail, results in a higher quality exchange of ideas.”

Thirdly, comments are a ghetto filled with second class citizens. Your opinion is less valued than that of the post’s author. This is why I added the miscellany to my site. Every user has as much power there as I do, including the ability to edit their own and others words.

Two two

brehaut.net has reached another milestone today. I am calling the current state version 2.2; Although it is the fourth major version of the code-base, it is the second revision to the design I launched in December of 06. Since then we have created 235 pages in the miscellany with 3495 revisions!

The design and layout got a shakeup, and the blog is back in an active form (and the old archives are all but gone). The geeks among you may appreciate the changes to macro system on the wiki (syntax highlighting for all!).

So thank you for your contributions, critiques and suggestions.

Feb 23 2009

A better blog

Some thoughts on a creating a better blog for myself from reading and studying sites I rate highly.

Why read a blog? I read blogs to follow one person’s attention, and to be directed to new ideas and gain new perspective on ideas I am already familiar with. Typically the focus of the blog will have a reasonable overlap with my own interests. I will also discover new things that I would not actively seek out myself.

Brevity is important. This is a lesson I learned from Twitter. I am happy to know about your lunch or trip to the zoo if I can digest it easily and move on. More detailed articles are better served by real pages or very focused blogs.

I have very little interest in comments. Sturgeon’s law applies doubly for blog comments. A communities social character is unavoidably tied to its technical details (see Group Enemy).

The only content I wish to see on my blog is interesting content. Pingbacks provide a possible solution here; If I am able to view a private report on posts that ping back, I can cherry-pick the most interesting and relevant responses for readers to see. No public commenting system would exist.

The design of writing interface is vital. Write and editing must be separate from posting. Quick, unedited thoughts should be discouraged by design. Software should warn about basic writing mistakes such as post length, double negation and passive voice.

See also