Search code examples
haskellghc

How To Write a Monad to Chain Computations Together


I am writing my first monad instance so please forgive if I'm missing something obvious.

I want to do something like this:

readStuffFromDatabase >>= function1 >>= ... >>= functionN >>= writeStuffToDatabase

function1 ... functionN are business logic. Any business logic can return DoNothing which should obviously prevent any further computation.

Here are my questions:

  1. Am I thinking about the problem in the right way? Can this approach lead to idiomatic code, good performance, etc. or is it already doomed?

  2. How should I define a type intended to chain arbitrary amounts of computation together? What's fuzzy to me is do all monad instances already do that and all I need is a vanilla monad instance? (Like Maybe?) Or do I need something more sophisticated?


Solution

  • Short version: Monad is almost certainly going to paint you into a corner. You need Applicative instead, or at most, a selective applicative.

    Suppose you go for a monad, name it M, and have some action like numEmployees :: M Int or something. Now I write:

    do
        n <- numEmployees
        if n > 10
            then computeTaxes
            else dollars 1000 <$ DoNothing
    

    To execute this action, you need to decide whether the else branch gets taken before knowing n. Not possible.

    The fundamental feature of monads that's in your way here is that later actions can inspect the values returned by earlier actions before deciding what to do. Applicative functors do not support that, and so are more amenable to the kind of static analysis you're hoping to do.