Haskell StateT and ExceptT chain - haskell

I am not very good haskell programer. I am tasked to write a compiler at my university and I have choosen haskell, as it is good tool for that purpose. I am using monads StateT and ExcepT, so I have types:
type Runner r s = StateT s (ExceptT LatteError IO) r
type RT r s = IO (Either LatteError (r, s))
I use it create walk a program tree and produce asm code and it works as I want. As main function for walking over tree I use
rProgram :: Program -> Runner [String] CompileState
and to unpack result I use function
runR program = runExceptT (runStateT (rProgram program) initialCompileState)
What I want to do not is to have some validators, like type check, ident existance check, and I know to write them. Lets tell I have
tcProgram :: Program -> Runner () TypeCheckState
ieProgram :: Program -> Runner () IdentExistanceState
I want to run them both in elegant way, and an failure is indicated by throwError. How to put many functions like them together?

lens has a zoom combinator which uses a lens to "zoom in" on a part of the state.
zoom :: Lens' s t -> State t a -> State s a
(As is usual in lens, the actual type of zoom is more complicated than that, but this is a simple way to think about it.)
So we have
zoom _1 . tcProgram :: Program -> Runner () (TypeCheckState, t)
zoom _2 . ieProgram :: Program -> Runner () (s, IdentExistenceState)
and so
liftA2 (>>) (zoom _1 . tcProgram) (zoom _2 . ieProgram) :: Program -> Runner () (TypeCheckState, IdentExistenceState)

Related

Best practices with monad transformers : to hide or not to hide 'liftIO'

I will preface this by saying that I am a novice Haskell programmer (tinkered with it sporadically over the years) but I have a fair few years on the counter when it comes to OOO and imperative programming. I am currently learning how to use monads & combining them via the use of monad transformers (assuming I've got the correct term).
While I am able to assemble/chain things together, I am finding it hard to build an intuition for what the best way and style is & how best to assemble/write those interactions.
Specifically, I am curious to know what the best practice (or at least your practice) is for using lift/liftIO and any flavour in between & if there is way (and benefit) to hide them as I am finding them rather 'noisy'.
Below is an example snippet which I have put together to illustrate what I mean :
consumeRenderStageGL' :: RenderStage -> StateT RenderStageContext IO ()
consumeRenderStageGL' r = do
pushDebugGroupGL (name r)
liftIO $ consumePrologueGL ( prologue r )
liftIO $ consumeEpilogueGL ( epilogue r )
consumeStreamGL ( stream r )
liftIO $ popDebugGroupGL
Some of the functions it calls make use of the state monad :
pushDebugGroupGL :: String -> StateT RenderStageContext IO ()
pushDebugGroupGL tag = do
currentDebugMessageID <- gets debugMessageID
liftIO $ GL.pushDebugGroup GL.DebugSourceApplication (GL.DebugMessageID currentDebugMessageID) tag
modify (\fc -> fc { debugMessageID = (currentDebugMessageID + 1) })
consumeStreamGL :: Stream -> StateT RenderStageContext IO ()
consumeStreamGL s = do
mapM_ consumeTokenGL s
logGLErrors
While most don't and just live in IO (meaning they have to be lifted):
consumePrologueGL :: Prologue -> IO ()
consumePrologueGL p = do
colourClearFlag <- setupAndReturnClearFlag GL.ColorBuffer ( clearColour p ) (\(Colour4 r g b a) -> GL.clearColor $= (GL.Color4 r g b a))
depthClearFlag <- setupAndReturnClearFlag GL.DepthBuffer ( clearDepth p ) (\d -> GL.clearDepthf $= d)
stencilClearFlag <- setupAndReturnClearFlag GL.StencilBuffer ( clearStencil p ) (\s -> GL.clearStencil $= fromIntegral s)
GL.clear $ catMaybes [colourClearFlag, depthClearFlag, stencilClearFlag]
logGLErrors
where
setupAndReturnClearFlag flag mValue function = case mValue of
Nothing -> return Nothing
Just value -> (function value) >> return (Just flag)
My question is : is there any way to hide the liftIO in consumeRenderStageGL' and more importantly would this be a good or a bad idea?
One way I can think of hiding/getting rid of the liftIO is to bring both my consumePrologueGL & consumeEpilogueGL into my state monad but this seems wrong in the sense that those function do not need (and should not) interact with it ; all this just to reduce code noise.
The other option I can think of is to simply create the lifted version of the functions and call them in consumeRenderStageGL' - this would reduce the code noise but be identical in execution/evaluation.
The third option, which is how my logGLErrors works is that I have used a type class which has an instance defined for both IO & my state monads.
I look forward to reading what your opinions, advices and practices are.
Thanks in advance!
There are a few solutions. A common one is to make your basic actions MonadIO m => m … instead of IO …:
consumePrologueGL :: (MonadIO m) => Prologue -> m ()
consumePrologueGL p = liftIO $ do
…
Then you can use them in StateT RenderStageContext IO () without wrapping, due to MonadIO m => MonadIO (StateT s m), and of course MonadIO IO where liftIO is the identity function.
You can also abstract over the StateT part using MonadState from mtl, so if you add another transformer above/below it, you won’t have the same issue of lifting from/to StateT.
pushDebugGroupGL
:: (MonadIO m, MonadState RenderStageContext m)
=> String -> m ()
Generally, a concrete stack of transformers types is fine, it just helps to wrap all your basic operations for convenience so that all the lifts are in one place.
mtl helps remove the lift noise from your code altogether, and working in a polymorphic type m means you have to declare which effects a function actually uses, and can substitute different implementations of all the effects (except for MonadIO) for testing. Using monad transformers as an effect system like this is great if you have few types of effects; if you want something finer-grained or more flexible, you’ll start hitting the pain points that make people reach for algebraic effects instead.
It’s also worth assessing whether you need StateT over IO. Typically if you’re in IO, you don’t need the pure state offered by StateT, so instead of StateT MutableState IO you might as well use ReaderT (IORef MutableState) IO.
It’s also possible to make that (or a newtype wrapper for it) an instance of MonadState MutableState, so your code using get/put/modify wouldn’t even need to change:
{-# Language GeneralizedNewtypeDeriving #-}
import Data.Coerce (coerce)
newtype MutT s m a = MutT
{ getMutT :: ReaderT (IORef s) m a }
deriving
( Alternative
, Applicative
, Functor
, Monad
, MonadIO
, MonadTrans
)
evalMutT :: MutT s m a -> IORef s -> m a
evalMutT = coerce
instance (MonadIO m) => MonadState s (MutT s m) where
state f = MutT $ do
r <- ask
liftIO $ do
-- NB: possibly lazier than you want.
(a, s) <- f <$> readIORef r
a <$ writeIORef r s
This combo of ReaderT & IO is a pretty common design pattern.

How to dispatch different types from a ContT?

I want to create a generalized form of IO based on ContT. I created a GADT to represent different IO actions:
data Cmd a where
PutChar :: Char -> Cmd ()
GetChar :: Cmd Char
I wrote a function that transforms these into IO commands for use in the IO monad like so:
continueIO :: Cmd a -> IO a
continueIO (PutChar c) = putChar c
continueIO GetChar = getChar
Here's what a sample usage of this should look like:
echoChar :: (Monad m) => ContT r m (Cmd a)
echoChar = ContT $ \k -> do
c <- k GetChar
k (PutChar c)
It should be run with something like runContT echoChar continueIO. However, the PutChar and GetChar commands conflict in their types. How can I dispatch both types from the same ContT?
P.S. Sorry if anything in this question is awkwardly worded. I'm trying to give myself a challenge here and I don't completely understand what I'm trying to do.
Edit: I am not restricted in my solution, and I do not have to use ContT.
Either your commands all need to be closures that return the same type (such as IO (), in which case you can’t do getChar) or you need to have a polymorphic result type that can hold either IO () or IO Char, and ContinueIO needs to take this as its argument. Then you need to decide what happens when you pass an IO Char to GetChar or nothing to PutChar. (This version could be a Monoid with <> = ContinueIO and mempty = id, and then you could foldMap over any Foldable structure.)

bind a monadic value (m2 a) inside some other monad m1

Working in a Coding Dojo today I tried the following
example :: IO ()
example = do input <- getLine
parsed <- parseOnly parser input
...
where parseOnly :: Parser a -> Either String a (from attoparsec) of course the compiler complained that Either .. is not IO .. essentially telling me I am mixing monads.
Of course this can be solved by
case parseOnly parser input of .. -> ..
which is kind of unelegant, I think. Also my guess is that somebody else had this problem earlier and the solution I think is related to monad transformers, but the last bits I cannot piece together.
It also reminded me of liftIO - but this is the other way around I think which solves the problem of lifting an IO action happening inside some surrounding monad (more precisely MonadIO - say for example inside Snap when one wants to print something to stdout while getting some http).
More general this problem seems to be for a Monad m1 and a (different) Monad m2 how can I do something like
example = do a <- m1Action
b <- m2Action
..
You can't, in general. The whole do block has to be one specific monad (because example needs to have some specific type). If you could bind an arbitrary other monad inside that do block, you'd have unsafePerformIO.
Monad transformers allow you to produce one monad combining the kinds of things multiple other monads can do. But you have to decide that all the actions in your do block use the same monad transformer stack to use those, they're not a way to arbitrarily switch monads mid do-block.
Your solution with case only works because you've got a particular known monad (Either) that has a way of extracting values from inside it. Not all monads provide this, so it's impossible to build a general solution without knowing the particular monads involved. That's why the do block syntax doesn't provide such a shortcut.
In general, monad transformers are for this kind of interleaving. You can use ExceptT
example :: IO (Either String ())
example = runExceptT $ do
input <- liftIO getLine
parsed <- parseOnly parser input
...
Note that parseOnly must return ExceptT String IO a for some a. Or better ExceptT String m a for any m. Or if you want parseOnly to return Either String a it's
example :: IO (Either String ())
example = runExceptT $ do
input <- lift getLine
parsed <- ExceptT $ return $ parseOnly parser input
...
But I think all you need is just
eitherToIO :: Either String a -> IO a
eitherToIO (Left s) = error s
eitherToIO (Right x) = return x
parseOnly :: ... -> String -> Either String Int
example :: IO ()
example = do
input <- getLine
parsed <- eitherToIO $ parseOnly parser input
...
You need to make that expression type check; just as in pure code. Here,
... = do a <- act1 -- m1 monad
b <- act2 -- m2 monad
...
de-sugars to:
... = act1 >>= (\a -> act2 >>= \b -> ...)
>>= is of signature:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
the outer bind is specialized with m1, so it expects that the expression inside parenthesis be of type: a -> m1 b, whereas the inner bind is specialized with m2, so the expression inside parenthesis will be of type a -> m2 b:
-- outer bind expects ( \a -> m1 b )
act1 >>= (\a -> act2 >>= \b -> ...)
-- inner bind results ( \a -> m2 b )
for this to type check, you need a function of signature m2 b -> m1 b in between the two; that is what lift does for a certain class of m2 and m1 monads: namely m1 ~ t m2 where t is an instance of MonadTrans:
lift :: (Monad m, MonadTrans t) => m a -> t m a

Haskell: Resume monadic computation inside IO

I'm trying to "resume" a monadic computation from within IO and fearing that I may be out of luck. The situation is the following:
ioBracketFoo :: (a - > IO b) -> IO b
withBar :: MonadIO m => (a -> m b) -> m b
withBar action = liftIO $ ioBracketFoo $ \foo -> runMagic (action f)
Basically I want to resume my (unknown) monadic computation from within ioBracketFoo. If it were not a bracketing function then I'd be able to get the resource using res <- liftIO getFoo and release it later, and I wouldn't have to resume my monadic computation from within IO.
Is there any other creative use of lift or similar to make this possible?
This problem is sloved by MonadBaseControl. MonadBaseControl provides the functions to store and restart a monadic computation. You'll require an additional dependency to MonadBaseControl, which will prevent unstorable monads from beeing used in your bracket-funciton, for example
There is a tutorial on fp-complete, that should answer all basic questions.

What is the name of this Monad Stack function?

I've got a bunch of stateful functions inside a State monad. At one point in the program there needs to be some IO actions so I've wrapped IO inside a StateT getting a pair of types like this:
mostfunctions :: State Sometype a
toplevel :: StateT Sometype IO a
To keep things simple I don't want pass the IO context into the main set of functions and I would like to avoid wrapping them in the monad stack type. But in order to call them from the toplevel function I need something akin to a lift, but I'm not trying to lift a value from the inner monad. Rather I want to convert the state in the StateT monad into something equivalent in the State monad. To do this I've got the following:
wrapST :: (State Sometype a) -> StateT Sometype IO a
wrapST f = do s <- get
let (r,s2) = runState f s
put s2
return r
This then get used to interleave things like the following:
toplevel = do liftIO $ Some IO functions
wrapST $ Some state mutations
liftIO $ More IO functions
....
It seems like a fairly obvious block of code so I'm wondering does this function have a standard name, and it is already implemented somewhere in the standard libraries? I've tried to keep the description simple but obviously this extends to pulling one transformer out of a stack, converting the wrapped value to the cousin of the transformer type, skipping the monads below in the stack, and then pushing the results back in at the end.
It may be a good idea to refactor your code to use the type StateT SomeType m a instead of State SomeType a, because the first one is compatible to an arbitrary monad stack. If you'd change it like this, you don't need a function wrapST anymore, since you can call the stateful functions directly.
Okay. Suppose you have a function subOne :: Monad m => State Int Int:
subOne = do a <- get
put $ a - 1
return a
Now, change the types of all functions like this one from State SomeType a to StateT SomeType m a, leaving m as is. This way, your functions can work on any monadic stack. For those functions, that require IO, you can specify, that the monad at the bottom must be IO:
printState :: MonadIO m => StateT Int m ()
printState = do a <- get
liftIO $ print a
Now, it should be possible to use both functions together:
-- You could use me without IO as well!
subOne :: Monad m => StateT Int m ()
subOne = do a <- get
put $ a - 1
printState :: MonadIO m => StateT Int m ()
printState = do a <- get
liftIO $ print a
toZero :: StateT Int IO ()
toZero = do subOne -- A really pure function
printState -- function may perform IO
a <- get
when (a > 0) toZero
PS: I use GHC 7, some of the libs changed midway, so it might be a bit different on GHC 6.
A more direct answer to your question: the function hoist does exactly what you're describing in a slightly more generic way. Example usage:
import Control.Monad.State
import Data.Functor.Identity
import Control.Monad.Morph
foo :: State Int Integer
foo = put 1 >> return 1
bar :: StateT Int IO Integer
bar = hoist (return . runIdentity) foo
hoist is part of the MFunctor class, which is defined like this:
class MFunctor t where
hoist :: Monad m => (forall a. m a -> n a) -> t m b -> t n b
There are instances for most monad tranformers, but not ContT.

Resources