the crab & musket


Micro-tutorial: liftM by accident

November 28, 2013

As a relatively new Haskeller, I’ve been mystified at the lift family of functions. They idea that they promote a pure function to do some computation in a monad makes sense, but I’ve never found uses for them in my code, and I think it’s because I don’t fully understand them. That changed yesterday, so I hope that my process will help other people in my position come to terms with liftM.

(Beware: there are probably lots of technically incorrect ways to describe monads and their operations below! I’d appreciate being corrected on them!)

I recently wrote a toy program that had to read matrices from user input. I first wrote it using this pattern:

str <- getLine
let mat = readMatrix str

Of course, getLine is from the Prelude (and has type IO String). readMatrix is from hmatrix. Its purpose is to read a String and construct a Matrix Double from it - which is represented by the type String -> Matrix Double. So I’m sure anybody reading this is fairly clear on why the code does what it does. strMat <- getLine “unboxes” the value of getLine, allowing us to use it as a pure String rather than an IO String, so we can give it to readMatrix to get a pure matrix value.

This pattern annoyed me slightly, since I would never make use of str again. I knew that, this being Haskell, there must me some way to simplify the two-line pair into a single line (or probably a single function call with lots of punctuation!). Fetching a value in a monad and operating on it with a pure function sounded like it should be a fairly common task.

The first step was to get rid of the do notation and see the actual underlying function calls. According to the wiki, the bind operator (>>=) is the result of desugaring the <- syntax. Bind takes a monadic value on the left-hand side, “unboxes” it, and feeds it to a monadic function on the right-hand side. So I could rewrite my two lines as one line with a bind:

mat <- getLine >>= \x -> return (readMatrix x)

Since binding is a monadic operation, you can’t just bind getLine directly to a pure function (like, getLine >>= readMatrix). The whole expression must return some monadic value, which we then purify using the <- notation after the bind has happened.

So I managed to condense my two lines into one line, but it’s still fairly ugly, with all that line noise in there. We can at least get rid of the lambda by using a pointfree style:

mat <- getLine >>= return . readMatrix

But this still smelled like boilerplate. Surely, I told myself, surely people need to perform some impure/monadic function, pass it to a pure function, and get an impure result back which they can purify by binding it. In fact, I could write a little utility function for it myself:

doSomething impureFn pureFn = impureFn >>= return . pureFn

And now, I could rewrite my input line like this:

mat <- doSomething getLine readMatrix

Suspecting that this function may already exist, I set off to Hoogle to find it. I discovered the type of my new function using GHCi:

ghci> :t doSomething
doSomething :: (Monad m) => m a1 -> (a1 -> r) -> m r

And Hoogle turned up liftM from the Control.Monad package as the first result, even though the arguments are flipped. So, my code above was now equivalent to:

mat <- liftM readMatrix getLine

Which is about as concise as I could ask for. So, if you ever need to perform a pure operation on a monadic value, try lifting your function! Here are the original and the final versions side-by-side:

-- Explicit
strMat <- getLine
let mat = readMatrix strMat

-- Lifted
mat <- liftM readMatrix getLine

fin