snak :: IO Text

Posts tagged haskell

0 notes

CPP with multi-line string literals

When you enable CPP language extension and compile a file that contains multi-line string literals, you’ll find that it fails to compile.

{-# LANGUAGE CPP #-}

test = "abc \
          \def"

This is because cpp expands backslashes at the end of lines. To workaround this problem, you can use cpphs instead.

{-# LANGUAGE CPP #-}
[-# OPTIONS_GHC -pgmP cpphs -optP --cpp #-}

test = "abc \
          \def"

You can specify an alternative preprocessor with -pgmP and options to the preprocessor with -optP. You need to use --cpp to tell cpphs to process command line options for cpp.

Filed under haskell

0 notes

Lifting a monadic computation through a stack of monad transformers, part 2

In the previous post, we defined liftFunc''' which lifts a computation in IO to MaybeT. If you do the same thing for StateT, you’ll get this function.

liftFunc''' :: ((forall a. StateT s IO a -> IO (a, s)) -> IO (b, s)) -> StateT s IO b
liftFunc''' f = let z s = f (flip runStateT s)
                in StateT $ \s -> z s

By comparing liftFunc''' for MaybeT and StateT, we’ll find that we can generalize liftFunc''' by introducing a type class and a type synonym family.

{-# LANGUAGE TypeFamilies, RankNTypes #-}

import Control.Monad (liftM)
import Control.Monad.Trans (MonadTrans, lift)
import Control.Monad.Trans.Maybe (MaybeT(MaybeT), runMaybeT)
import Control.Monad.Trans.State (StateT(StateT), runStateT, put)
import Data.Tuple (swap)

class MonadTrans t => MonadTransFunc t where
    type C t :: * -> *
    liftFunc :: Monad m => ((forall a. t m a -> m (C t a)) -> m (C t b)) -> t m b

The type family C denotes a container that carries a monadic value in the base monad. It’s Maybe for MaybeT and (a, s) for StateT s. For example, we can define an instance of this class for MaybeT.

instance MonadTransFunc MaybeT where
    type C MaybeT = Maybe
    liftFunc f = MaybeT $ f runMaybeT

Although we want to define an instance for StateT like:

instance MonadTransFunc (StateT s) where
    type C (StateT s) a = (a, s)
    liftFunc f = StateT $ \s -> f $ flip runStateT s

we cannot do this because it applies two type parameters to C. So we have to swap the types in the tuple.

instance MonadTransFunc (StateT s) where
    type C (StateT s) = (,) s
    liftFunc f = StateT $ \s -> liftM swap $ f (liftM swap . flip runStateT s)

Now you can lift computations using liftFunc.

testFunc0 :: IO a -> IO a
testFunc0 f = print "testFunc0" >> f

testFunc1 :: (Int -> IO a) -> IO a
testFunc1 f = print "testFunc1" >> f 1

maybeFunc0 :: MaybeT IO Int
maybeFunc0 = do lift $ print "maybeFunc0"
                return 0

stateFunc1 :: Int -> StateT Int IO Int
stateFunc1 n = do lift $ print $ "stateFunc1: " ++ show n
                  put n
                  return n

maybe0 = runMaybeT go
    where
      go = liftFunc $ \run -> testFunc0 $ run $ maybeFunc0

state1 = runStateT go 0
    where
      go = liftFunc $ \run -> testFunc1 $ \x -> run $ stateFunc1 x

Note that you can lift a computation through two levels by applying liftFunc twice.

maybeStateFunc1 :: Int -> MaybeT (StateT Int IO) Int
maybeStateFunc1 n = do lift $ lift $ print $ "maybeStateFunc1: " ++ show n
                       lift $ put n
                       return n

maybeState1 = runStateT (runMaybeT go) 0
    where
      go = liftFunc $ \runMaybe ->
               liftFunc $ \runState ->
                   testFunc1 $ \x -> runState $ runMaybe $ maybeStateFunc1 x

But in most case, you may want to lift computations in a base monad directly through the stack of monad transformers as liftIO and liftBase do. How can we do that?

Filed under haskell

1 note

Lifting a monadic computation through a stack of monad transformers, part 1

We’ve already know that we can lift a monadic computation using lift of MonadTrans. For example, we can lift print to MaybeT monad like:

test = runMaybeT go
    where
      go = lift $ print "Test"

But how can we lift a computation that takes monadic computations as its arguments? For example, how can we define this liftFunc1?

testFunc1 :: (Int -> IO a) -> IO a
testFunc1 f = f 1

func1 :: Int -> MaybeT IO Int
func1 n = lift (print n) >> return n

test1 = runMaybeT go
    where
      go = liftFunc1 testFunc1 func1

The type signature of this function may be like this:

liftFunc1 :: ((a -> IO b) -> IO b) -> (a -> MaybeT IO b) -> MaybeT IO b

and its definition would be something like this one.

liftFunc1 f g = let h x = liftM fromJust $ runMaybeT $ g x
                    z = f h
                in MaybeT $ liftM Just z

But because f needs to return b, we have to get a value from Maybe and re-wrap it in Just. As you’ve notice, it doesn’t work if g returns Nothing.

So we allow the inner computation to wrap its return value with Maybe. The new type signature would be:

liftFunc1 :: ((a -> IO (Maybe b) -> IO (Maybe b)) -> (a -> MaybeT IO b) -> MaybeT IO b

and the definition would be:

liftFunc1 f g = let h x = runMaybeT $ g x
                    z = f h
                in MaybeT z

The basic idea is to run the outer monad (MaybeT, this case) and wrap the monadic value with a container (Maybe) and make the inner monad return it (IO (Maybe b)).

Note that because we made the inner computation to wrap its return value, the function must be polymorphic. You can’t lift a computation like this one.

testFunc :: (Int -> IO Int) -> IO Int

We have defined liftFunc1 that lifts a monadic computation that takes a function that takes one argument. How about a function that takes no argument or two arguments? Those will be:

liftFunc0 f g = let h = runMaybeT g
                    z = f h
                in MaybeT z

liftFunc2 f g = let h x y = runMaybeT $ g x y
                    z = f h
                in MaybeT z

Now I’d like to define a function that can be used for all of these computations. The very simple approach is moving h to callers. If we define liftFunc' as

liftFunc' :: (a -> IO (Maybe b)) -> a -> MaybeT IO b
liftFunc' f g = let z = f g
                in MaybeT z

we can write a caller like:

test' = runMaybeT go
    where
      go = liftFunc' testFunc2 (\x y -> runMaybeT $ func2 x y)

This is fine, but we don’t make a caller to call runMaybeT directly, because we’d like to make a caller to be used with other monad transformers in the future. So we made liftFunc'' to pass runMaybeT to g.

liftFunc'' :: (a -> IO (Maybe b)) -> ((MaybeT IO c -> IO (Maybe c)) -> a) -> MaybeT IO b
liftFunc'' f g = let z = f (g runMaybeT)
                     in MaybeT z

test'' = runMaybeT go
    where
      go = liftFunc'' testFunc2 (\run x y -> run $ func2 x y)

As you’ve noticed, because g will be just given back to f, we don’t need to pass g to liftFunc''. Instead of passing runMaybeT to g, we pass it to f and make liftFunc''' not take g as an argument.

liftFunc''' :: ((MaybeT IO a -> IO (Maybe a)) -> IO (Maybe b)) -> MaybeT IO b
liftFunc''' f = let z = f runMaybeT
                in MaybeT z

test''' = runMaybeT go
    where
      go = liftFunc''' $ \run -> testFunc2 $ \x y -> run $ func2 x y

With liftFunc''' you can lift a computation that takes a monadic computation that takes any number of arguments.

liftFunc''' $ \run -> testFunc0 $ run func0
liftFunc''' $ \run -> testFunc1 $ \x -> run $ func1 x
liftFunc''' $ \run -> testFunc2 $ \x y -> run $ func2 x y

But it doesn’t allow to take more than one computations that return different types. For example,

testFunc01 :: IO a -> (Int -> IO b) -> IO b
testFunc01 f g = f >> g 0

runMaybeT $ liftFunc''' $ \run -> testFunc01 (run $ return 'a') (\n -> run $ return n)

cannot type-check. To make this type-check, we have to make run function polymorphic by adding an explicit type signature like:

liftFunc''' :: ((forall a. MaybeT IO a -> IO (Maybe a)) -> IO (Maybe b)) -> MaybeT IO b

Note that you need to enable RankNTypes extension.

Filed under haskell

0 notes

Catching an exception using MonadCatchIO

Imagine you’re working with monad transformers and want to catch an exception. But because the signature of catch is Exception e => IO a -> (e -> IO a) -> IO a, you need to unwrap monad stacks to do it.

For example, you can catch an exception inside MaybeT monad like:

{-# LANGUAGE DeriveDataTypeable, NoMonomorphismRestriction, ScopedTypeVariables #-}

import Control.Exception
import Control.Monad.IO.Class
import Control.Monad.Trans.Maybe
import Data.Typeable
import Prelude hiding (catch)

data TestException = TestException deriving (Show, Typeable)

instance Exception TestException

test = runMaybeT $ catchMaybeT (liftIO $ throwIO TestException)
                               (\(e :: TestException) -> return 0)

catchMaybeT m f = MaybeT $ runMaybeT m `catch` (\e -> runMaybeT $ f e)

MonadCatchIO class offers this kind of handlers for most monad transformers. You can use Control.Monad.CatchIO.catch instead of catchMaybeT above. It also provides bracket families.

But care must be taken when you use bracket with some monad transformers, because the final computation may not run.

For example, in this code, “End” will never be printed.

test = runMaybeT $ CatchIO.bracket (liftIO $ print "Start")
                                   (const $ liftIO $ print "End")
                                   (const empty)

This is because the final computation runs just after the main computation if no exception is thrown, and once a computation becomes Nothing, the computations following that computation will become Nothing in MaybeT monad. This is just the same as

runMaybeT $ empty >> liftIO (print "x")

never printing “x”.

The same goes for ErrorT monad.

Another point I’d like to mention is about a state when each computation runs in StateT.

{-# LANGUAGE DeriveDataTypeable, ScopedTypeVariables #-}

import Control.Exception
import Control.Monad.CatchIO as CatchIO
import Control.Monad.IO.Class
import Control.Monad.Trans.State
import Data.Typeable

data TestException = TestException deriving (Show, Typeable)

instance Exception TestException

test f = runStateT go "Init"
    where
      go = do CatchIO.bracket (updateState "Start")
                              (const $ updateState "End")
                              (const f)
                  `CatchIO.catch` \(_ :: TestException) -> updateState "Catch"
              updateState "Last"

updateState at = do printState at
                    put at
                    return at

printState at = get >>= \state -> liftIO $ print $ "At " ++ at ++ ": " ++ state

test1 :: IO (String, String)
test1 = test $ do updateState "Func"
                  liftIO $ throwIO TestException

In this code, you’ll find that the final computation runs with the state at the start, and the catch computation runs with the initial state, if an exception is thrown. I mean any changes made to the state in the main computation are discarded, although any changes in the base IO monad won’t be reverted —- actually it’s impossible.

Filed under haskell

0 notes

MonadBase is a generalized MonadIO

When you work with monad transformers, you may lift a function using lift. For example, this code lifts print from the base IO monad.

test = runMaybeT go
  where
    go = do lift $ print "test"
            return 3

But with lift you need to lift multiple times. For example, this code doesn’t compile.

test5 = runMaybeT (runStateT go 0)
    where
      go = do lift $ print "test"
              return 3

You need to lift two times explicitly.

test5 = runMaybeT (runStateT go 0)
    where
      go = do lift $ lift $ print "test"
              return 3

With MonadIO, you can lift a function in the base IO monad through arbitrary levels. Now you can write:

test5 = runMaybeT (runStateT go 0)
    where
      go = do liftIO $ print "test"
              return 3

MonadBase is a generalized version of MonadIO that allows you to lift a function in a base monad through arbitrary levels. The base monads include List, Maybe, ST, STM, IO and so on.

For example, you can access STRef in the base monad directly using liftBase.

test = runST go
    where
      go = do r <- newSTRef 0
              runMaybeT $ runStateT (go2 r) 0
              readSTRef r
      go2 r = do liftBase $ writeSTRef r 10
                 return 3

Note that monad transformers such as StateT or ReaderT may not be a base monad even if it is used directly on top of Identity. That means State or Reader may not be a base monad.

Filed under haskell

5 notes

for_ is whenJust

Sometimes, I defined a utility function whenJust as follows:

whenJust :: Monad m => Maybe a -> (a -> m ()) -> m ()
whenJust = flip $ maybe (return ())

and use it like:

whenJust x $ print

But finally I found that Data.Foldable.forM_ is equivalent to this function thanks to Proposal: add Control.Monad.whenJust ∷ (Monad m) ⇒ Maybe α→(α→ m ()) → m (). Actually, this is obvious because Maybe is a container that may have one element. You can also use Data.Foldable.for_ for applicative functors. Now you can write:

for_ x $ print

without defining your whenJust.

Filed under haskell