0

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
Jules
  • 14,200
  • 13
  • 56
  • 101
  • Do you know how to do it *without* transformers? Can you make an `IO + State` monad by hand? – PyRulez Apr 13 '16 at 18:53
  • The way this function is written currently shows a pretty critical misunderstanding of the "monad" abstraction. before moving onto transformers, you should first try to implement your current function so as to not be partial, and potentially use monad combinators. – user2407038 Apr 13 '16 at 19:16
  • @HaskellFun Do you understand the State monad by itself (how to implement it)? – PyRulez Apr 13 '16 at 19:18
  • Yes, I can implement bind and return. –  Apr 13 '16 at 19:43

1 Answers1

3

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.
PyRulez
  • 10,513
  • 10
  • 42
  • 87