combining IO monad with State Monad in example - haskell

I created simple evaluator for statements.
I would like to do it using transformers - mix IO monad with State.
Could somebody explain how to do it ? It is something that I can't deal with it - transformers.
execStmt :: Stmt -> State (Map.Map String Int) ()
execStmt s = case s of
SAssigment v e -> get >>= (\s -> put (Map.insert v (fromJust (runReader (evalExpM e) s)) s))
SIf e s1 s2 -> get >>= (\s -> case (fromJust (runReader (evalExpM e) s)) of
0 -> execStmt s2
_ -> execStmt s1
)
SSkip -> return ()
SSequence s1 s2 -> get >>= (\s -> (execStmt s1) >>= (\s' -> execStmt s2))
SWhile e s1 -> get >>= (\s -> case (fromJust (runReader (evalExpM e) s)) of
0 -> return ()
_ -> (execStmt s1) >>= (\s' -> execStmt (SWhile e s1)))
execStmt' :: Stmt -> IO ()
execStmt' stmt = putStrLn $ show $ snd $ runState (execStmt stmt) Map.empty

Here's a basic program outline
newtype StateIO s a = SIO {runSIO :: s -> IO (a, s)}
put :: s -> StateIO s ()
put s' = SIO $ \_s -> return ((), s')
liftIO :: IO a -> StateIO s a
liftIO ia = SIO $ \s -> do
a <- ia
return (a, s)
instance Functor (StateIO s) where
fmap ab (SIO sa) = SIO $ \s -> do
(a, s') <- sa s
let b = ab a
return (b, s')
instance Applicative (StateIO s) where
pure a = SIO $ \s -> return (a, s)
(SIO sab) <*> (SIO sa) = SIO $ \s -> do
(ab, s' ) <- sab s
(a , s'') <- sa s'
let b = ab a
return (b, s')
StateIO s a is something that takes an input state (of type s), and returns an IO action to produce something of type a as well as a new state.
To check for understanding, do the following
Write a value of get :: StateIO s s which retrieves the state.
Write an instance for Monad (StateIO s) (it will be similar to the code above).
Finally, and this is the big step to understanding transformers, is to define newtype StateT m s a = StateT {run :: s -> m (a, s)}, and translate the above code to that (with the constraint Monad m). This will show you how monad transformers work.

Related

Haskell Change state in IO function

I'm trying to update a record in an IO-function. I have tried to use the state-monad without success. I saw a comment somewhere that it was possible to solve a similar problem with the state-monad. Is it possible to use the State-monad to do this or do I have to use a monad transformer? If so I would be grateful for a short explanation on how to do it.
{-# LANGUAGE GADTs #-}
data CarState = CS {color :: String }
initState :: CarState
initState = CS {color = "white"}
data Car where
ChangeColor :: String -> Car
func :: Car -> CarState -> IO ()
func (ChangeColor col) cs = do
putStrLn ("car is " ++ show(color cs))
-- Change state here somehow
-- colorChange "green"
putStrLn ("car is now" ++ show(color cs))
main :: IO ()
main = func (ChangeColor "green") initState
colorChange :: String -> MyState CarState String
colorChange col = do
cs <- get
put $ cs {color = col}
return col
data MyState s a = St (s -> (a,s))
runSt :: MyState s a -> s -> (a,s)
runSt (St f) s = f s
evalSt :: MyState s a -> s -> a
evalSt act = fst . runSt act
get :: MyState s s
get = St $ \s -> (s,s)
put :: s -> MyState s ()
put s = St $ \_ -> ((),s)
instance Monad (MyState s) where
return x = St $ \s -> (x,s)
(St m) >>= k = St $ \s_1 -> let (a, s_2) = m s_1
St k_m = k a
in k_m s_2
instance Functor (MyState s) where
fmap f (St g) = St $ \s0 -> let (a, s1) = g s0
in (f a, s1)
instance Applicative (MyState s) where
pure a = St (\s -> (a,s))
(<*>) (St sa) (St sb) = St (\s0 -> let (fn, s1) = sa s0
(a, s2) = sb s1
in (fn a, s2))
In Haskell you cannot mutate data in place, ever, by any mechanism. At all.1
The way state updates are modeled in Haskell is by producing a new value, which is identical to the old value, except for the "updated" bit.
For example, what you're trying to do would be expressed like this:
func :: Car -> CarState -> CarState
func (ChangeColor c) cs = cs { color = c }
1 Well, ok, technically you can sometimes, but it only works for data that has been arranged in advance to be mutable, and it is usually quite cumbersome. Not a normal way to write programs.

Haskell: Counter-intuitive type checking going on

So I have these type:
newtype StateT s m a = StateT {runStateT :: s -> m (a, s)}
data MTa a = FailTa Exception
| DoneTa {unpackDoneTa :: (a, O)}
deriving Show
type O = String
type Exception = String
type State = Int
I made (State s m) an instance of the Functor, Applicative, and Monad classes like so:
instance (Monad m) => Functor (StateT s m) where
fmap f t = StateT $ \is -> do
~(a, s) <- runStateT t is
return (f a, s)
instance (Monad m) => Applicative (StateT s m) where
pure = return
StateT f <*> StateT t = StateT $ \is -> do
~(ta, ts) <- t is
~(fa, fs) <- f ts
return (fa ta, fs)
instance (Monad m) => Monad (StateT s m) where
return a = StateT $ \s -> return (a, s)
StateT m1 >>= k = StateT $ \s -> do
~(a, s1) <- m1 s
let StateT m2 = k a
m2 s1
I also made MTa an instance of the Functor, Applicative, and Monad classes:
instance Functor MTa where
_ `fmap` (FailTa e) = FailTa e
f `fmap` (DoneTa (a, o)) = DoneTa (f a, o)
instance Applicative MTa where
pure = return
_ <*> (FailTa e) = FailTa e
FailTa e <*> _ = FailTa e
DoneTa (f, x) <*> DoneTa (a, y) = DoneTa (f a, y ++ x)
instance Monad MTa where
return a = DoneTa (a, "")
m >>= f = case m of
FailTa e -> FailTa e
DoneTa (a, x) -> case (f a) of
FailTa e1 -> FailTa e1
DoneTa (b, y) -> DoneTa (b, x ++ y)
I then have this function:
incTaState :: StateT State MTa ()
incTaState = StateT $ \s -> return ((), s+1)
Am I right to think that return ((), s+1) will evaluate to DoneTa (((), s+1), ""). If so, doesn't that mean that its type is MTa ((), State). Why does incTaState typecheck to StateT State MTa ()? When I run this: :t DoneTa ((), "") in a console, it evaluates to DoneTa ((), "") :: MTa (). Am I not interpreting the return part of incTaState correctly?
The question can almost be summarized like so: if Done ((), "") typechecks to MTa (), how is it that incTaState typechecks to StateT State MTa ()? Doesn't DoneTa (((), s+1), ""), the resolution of return ((), s+1), typecheck to MTa (((), State), O) making incTaState a type of StateT State MTa ((), State) not what is specified?
Please fell free to be verbose (-vvv).
Your consideration is much appreciated. Peace.
Below is removed as I made a mistake by entering a 3-tuple. Thanks #HTNW.
I suspect I'm not because when I run :t (StateT $ \s -> DoneTa (((), s+1, ""))) I get the following error:
• Couldn't match expected type ‘((a, b), O)’
with actual type ‘((), b, [Char])’
• In the first argument of ‘DoneTa’, namely ‘(((), s + 1, ""))’
In the expression: DoneTa (((), s + 1, ""))
In the second argument of ‘($)’, namely
‘\ s -> DoneTa (((), s + 1, ""))’
• Relevant bindings include s :: b (bound at <interactive>:1:12)
incTaState :: StateT State MTa ()
incTaState = StateT $ \s -> return ((), s+1)
\s -> ((), s+1) :: State -> ((), State)
-- You were correct
\s -> return ((), s + 1) :: State -> MTa ((), State)
-- The type of that function matches up with StateT
-- We can set s = State, m = MTa, and a = ()
StateT s m a = s -> m (a , s )
StateT State MTa () = State -> MTa ((), State)
-- So:
StateT $ \s -> return ((), s+1) :: StateT State MTa ()
-- QED
When you run StateT $ \s -> DoneTa ((), s+1, ""), the issue is that DoneTa :: (a, String) -> MTa a, with a 2-tuple, but you are passing it ((), s + 1, "") :: ((), State, String), a 3-tuple. Add more nesting: StateT $ \s -> DoneTa (((), s + 1), "") (where (((), s + 1), "") :: (((), State), String), a 2-tuple with a 2-tuple inside it).

State Monad then (>>)

I would like to know the definition of >> for the Haskell state monad.
By my guess it pass one state to another:
(>>) :: State s a -> State s b -> State s b
State a >> State b = State $ \x -> b $ snd ( a x )
or
State a >> State b = State $ b . snd . a
Is this correct?
You're pretty much right. >> is actually more general than you suggest, but you can certainly use it with the type signature you indicate. If you're using State from its usual home, Control.Monad.Trans.State.Strict, or its home away from home, Control.Monad.State.Strict, State is actually just a type synonym:
type State s = StateT s Identity
where Identity is from Data.Functor.Identity and defined
newtype Identity x = Identity x
and StateT is defined
newtype StateT s m a = StateT {runStateT :: s -> m (a, s)}
So State s a is just a newtype wrapper around
s -> Identity (a, s)
This is essentially the same as the definition you imagine, but it allows State s to be compatible with the monad transformer StateT s, which is used to add state to arbitrary Monads.
instance Monad m => Monad (StateT s m) where
return a = StateT $ \s -> return (a, s)
StateT g >>= f = StateT $ \s -> g s >>= \(r,s') -> runStateT (f r) s'
So
StateT g >> StateT h = StateT $ \s -> g s >>= \(_,s') -> h s'
= StateT $ \s -> h $ snd $ runIdentity (g s)
= StateT $ h . snd . runIdentity . g
Irrelevant side note
The definition of StateT annoys me, because in my opinion it puts the elements of the pairs in the wrong order. Why wrong? Because mapping over (a, s) changes s while leaving a alone, and that is not what happens when mapping over a state transformer. End result: poor intuition.
I think this Wikipedia page gives a definition for (>>=) for the State monad:
m >>= f = \r -> let (x, s) = m r in (f x) s
Since (>>) is implemented in terms of (>>=) as follows:
m >> k = m >>= \_ -> k
one can derive the definition for (>>) for the state monad:
m >> k = \r -> let (x, s) = m r in ((\_ -> k) x) s
or when removing the noise:
m >> k = \r -> let (x, s) = m r in k s
Now since x does not play a part in the in clause, you can indeed use snd to get s, which can thus be rewritten to:
m >> k = \r -> k $ snd m r

Extracting nested monadic result: m (m a) -> m a

I have a function
parseArgs :: [String] -> StdGen -> IO ()
which selects the function to run. The main looks like
main = parseArgs <$> getArgs <*> getStdGen >>= id
The problem I have, parseArgs <$> getArgs <*> getStdGen is of type IO (IO ()), which I extract using (>>= id) which is of type Monad m => m (m b) -> m b. Is there a way to avoid requiring the "extraction" of the value while having just a single line function?
The easiest way would be with join:
main = join $ parseArgs <$> getArgs <*> getStdGen
Personally, I would prefer the form
main = join $ liftM2 parseArgs getArgs getStdGen
where
join :: Monad m => m (m a) -> m a
liftM2 :: Monad m => (a -> b -> r) -> m a -> m b -> m r
Or just use a do
main = do
args <- getArgs
gen <- getStdGen
parseArgs args gen
You can define an operator for this:
infixl 4 <&>
(<&>) :: Monad m => m (a -> m b) -> m a -> m b
f <&> x = f >>= (x >>=)
If you have a function of type
f :: Monad m => (a1 -> a2 -> ... -> an -> m b) -> m a1 -> m a2 -> ... -> m an -> m b
then you can write
fx :: Monad m => m b
fx = f <$> x1 <*> x2 <*> ... <&> xn
where each xi has type m ai.
In your case it would be simply
parseArgs <$> getArgs <&> getStdGen
You could pair up the arguments and put them through a single bind:
main = uncurry parseArgs =<< (,) <$> getArgs <*> getStdGen
This avoids the extraction from nested IO. Admittedly it's no shorter but I find it easier to think about.
It fits a general pattern of doTheWork =<< getAllTheInputs which might be the way you'd end up arranging things anyway, if the code was more complicated.

What is a good name for this state-like monad

This is something of a combination of State and Writer. I have checked the monad laws.
newtype M s a = M { runM :: s -> (s,a) }
instance (Monoid s) => Monad (M s) where
return = M . const . (mempty,)
m >>= f = M $ \s ->
let (s' ,x) = runM m s
(s'',y) = runM (f x) (s `mappend` s')
in (s' `mappend` s'', y)
StateWriter seems kinda lame.
"Introspective Writer"? It seems that the interesting you can do with it (that you can't do with Writer) is to write an introspect function that examines the state/output and changes it:
introspect :: (s -> s) -> M s ()
introspect f = M $ \s -> (f s, ())
I can't see that you can do this for writer, I think you'd have to make do with a post-transformer instead:
postW :: Writer w a -> (w -> w) -> Writer w a
postW ma f = Writer $ let (w,a) = getWriter ma in (f w,a)
Monoidal State. MonoState.MState. AccumState.
Maybe call SW (Statefull Writer), I think short names are rather intuitive and save some typing.

Resources