Monads are Inversion of Control au naturel

Ted Neward on Twitter had the following somewhat astounding conversation:

Why do you keep insisting monads are goodness? What purpose do they serve in an impure functional environment like F#? (cite)

It’s just that if prospective F#’ers *have* to know monads to use F#, then F# is doomed. (cite)

If we’re OK with F# remaining niche, then OK, long live the monad! But I think it has more potential than that. (cite)

For a long time, I struggled with monads. I didn’t get what they were, or why I wanted to use them. I even had an awkard part in my Ruby.MN presentation of OCaml where I punted on them and then my helpful co-blogger pointed out I used them without realizing it in my presentation.

Since then, I have started to really grok monads, and it started with a realization: all of the Spring Inversion of Control stuff I’m so fond of are really monads done in an awkward OO style. So for all the scariness of the ominous name “monad”, and for all the hype about how awesome they are, they’re really just an idea the Java community is familiar (and happy) with expressed in a more direct way.

As an example, let’s consider an inversion of control class near and dear to my heart, JdbcTemplate. Now, JdbcTemplate is a collection of methods built off of a DataSource. While some of the methods are essentially utility methods (e.g. execute(String)), some of them are a bit more interesting. In particular, let’s look at query(String,RowCallbackHandler).

Used in Java, an example usage might be something like this:

final List<Integer> ints = new ArrayList<Integer>();
jdbcTemplate.query("select int_column from some_table", new RowCallbackHandler() { 
    void processRow(ResultSet rs) throws SQLException {
        ints.add(rs.getInt(1));
    }
});

(Please note that there are more appropriate methods on JdbcTemplate to implement this behavior, but I wanted a simple yet non-trivial case to work from.)

Based on the Java, it’s not easy to see the monad — you kind of have to turn your head and squint. But things become clearer when you do the same code in Groovy.

def ints = []
jdbcTemplate.query("select int_column from some_table", { ResultSet rs -> 
    ints << rs.getInt(1)
} as RowCallbackHandler);

So now we see that what we’re really doing is passing a closure into the method — so we’re doing some kind of functional programming here, just with a veneer of OO. What we’re doing is being provided a pre-configured ResultSet that we can do some processing on, but which is managed by the surrounding context.

It’s easy to imagine the same kind of code in OCaml.

let ints = ref [];;
let result_set_handler = fun rs -> ints := (get_int rs 1)::!ints in
query jdbcTemplate "select int_column from some_table" result_set_handler;;

Or, put more monad-y…

let ints = ref [];;
let jdbcTemplate = bind_data dataSource in
let sqlTemplate = bind_sql jdbcTemplate "select int_column from some_table" in
let result_set_handler = fun rs -> ints := (get_int rs 1)::!ints in
let resultTemplate = bind_row_handler sqlTemplate result_set_handler in
return_result resultTemplate;;

The monadic nature of inversion of control gets even more obvious if you consider a method like query(PreparedStatementCreator psc, PreparedStatementSetter pss, ResultSetExtractor rse) — it’s easy to envision a monad consisting of the DataSource, then binding to a a PreparedStatementCreator, then binding to a PreparedStatementSetter, then binding to a ResultSetExtractor, and finally returning. It is really nothing but a series of functions being bound into a context.

At this point, it should be clear that both monads and inversion of control are doing the same thing: they’re encapsulating context/change/state/patterns and providing stability by limiting the possible interactions with that context/change/state/pattern.

In the case of JdbcTemplate, it is encapsulating the standard patterns for working with JDBC calls, including whole swaths of nested try/catch blocks and error handling. By not allowing access to the connection or the prepared statement, it actually improves the clarity and stability of the code — after all, the connection and the prepare statement are implementation details, not meaningful parts of the algorithm.

Monads do the same thing: they express steps in the algorithm while abstracting away implementation details. Now, they’re much more powerful than the inversion of control pattern, because there isn’t this OO concept getting in the way of the pure functional goodness, but ultimately, monads and inversion of control are expressing the same kind of solution in different paradigms. These kinds of bridges are what we need to identify to help “line-of-business” developers move from OO to functional development.

Related posts:

  1. Back in control of my Perl modules
This entry was posted in Classic, Programming Language Punditry. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.
  • Brian

    By George, I think he’s got it.

    There is an interesting contrast, I think, between Lisp and Haskell. In Lisp, all code is data. A function is nothing more than a list of operations to be performed. This leads naturally to the concept of Macros (in the Lisp sense)- you can operate on functions (as lists) as easily as on any other list.

    Haskell, on the other hand, is precisely the other way around- all data is code. Laziness makes this explicit- under lazy evaluation, you don’t have an int, for example, you have a piece of code that, when executed (forced), evaluates to an int. This leads inevitably (if note quite as naturally as code-is-data leads to macros) to monads- as monads are just a way to constrain the context the code that produces the given value executes in.

    A monad is just a way of saying “this code needs to execute in a time and place where the condition X is true”. One condition that you may want to enforce is “this code needs to execute where we have an open connection to the database”. Another one might be “this code needs to execute where we can do I/O” or “this code needs to be in a transaction” or even “this code needs to be within a try/catch for the following exception”.

  • http://hamletdarcy.blogspot.com Hamlet D\’Arcy

    The Java 7 ARM proposal is (was?) a good usage of this. Bob Martin calls it the Hollywood principle: Don’t call us we’ll call you. But is this really all there is to monads? This sounds like a starting point for conceptualizing monads rather than a complete yet terse explanation.

  • http://www.smokejumperit.com Robert Fischer

    @Hamlet

    This post is written for OO-heavy people who are breaking into the functional setting (e.g. Ted Neward). It’s intended to make them seem less scary and provide a justification for their relevance — insofar as inversion of control is useful, monads are at least that useful.

    The thing that’s weird about monads is the stunts that are pulled with them — stunts like STM, message passing, and parallelism.

  • Pingback: Why We Don’t Need Anonymous Inner Classes for Groovy/Grails | Enfranchised Mind

  • http://suereth.blogspot.com Josh Suereth

    Ok, What I don’t get here is that you’re saying monads are like Spring’s inversion of control, but you don’t use inversion of control in the post, simply the Spring JDBC libraries, which are monadic and closure based.

    Spring’s inversion of control isn’t about passing annoynmous-inner-classs-closures, but about making sure you are passed in objects instead of statically accessing them (i.e. avoiding singletons). I believe spring recognized the benefits of ARM and Closure-like syntax early, which is why it has great “wrapper” libraries for various java technologies. However, I don’t think they have anything to do with the IoC container (which is dependency injection based).

    While I agree with the content of the post, I believe your definition for Inversion of Control is a bit off, and confused me for a bit. Yes there is an “inversion” to how you think about using objects, so in that sense it would be an inversion of control, but in the context of how it’s used and taught by Spring, I believe they’re mostly referring to dependency injection.

  • JS

    @Brian

    If…

    ” In Lisp, all code is data”

    and…

    “Haskell, on the other hand, is precisely the other way around- all data is code.”

    What is…

    http://liskell.org/ ?

  • Gustavs

    @JS

    An alternate syntax and code manipulation stage on top of an existing Haskell implementation.

  • Brian

    Gustavs: I think it’s more than that. Whether it’s a good idea or not remains to be seen, and I think that on balance I’m negative on the idea. Simply because two concepts are powerful doesn’t mean they’ll place nice together. I mean, both peanut butter and bacon are tasty, but they don’t go into the same dish (unless you’re Torg or Riff).

  • Pingback: Enfranchised Mind » Why We Don’t Need Anonymous Inner Classes for Groovy/Grails

  • Categories