I was working on a simple imperative language interpreter, mostly for the purpose of demonstration of scoping and parameter passing. It’s more like a debugger than an interpreter. Anyway, I guess it’s not important in this post. What I really want to document here is several refactorings I have done on the program.

  • The use of liftM function. I should have used this function more often than I did. It’s very nice and powerful indeed. It lifts any function to a monadic level. Take a look at the type and it tells you what it does:
    liftM :: Monad m => (a -> b) -> m a -> m b

    So whenever we have some code like this:

    x <- m return f x

    we can refactor it as:

    liftM f m
  • OK, this is not really any complicated trick, but I keep ignoring it all the time. I believe this would happen all the time to other functional programmers. Once we get so used to the do notation, we forget the most basic stuffs. I found myself often writing codes like this:
    x <- m f x

    What I really meant is just m >>= f , especially when f is somehow complicated and buried deeply. I should always keep this one in mind.

  • This one might do more confusion than clarity to newbies. But to me, this makes codes shorter and more readable. If we have two bindings and then apply one function to them, we might just replace the bindings with two >>=’s. For example, if you have something like this: 
    x <- m1 y <- m2 f x y

    You can replace the above codes with:

    m1 >>= (m2 >>=) . f

    Very neat, isn’t it? But viewer’s discretion advised :P