I'm writing interpreter in haskell. I want to do that with monads.
I already created parser, so I have a lot of functions :: State -> MyMonad State
, and I can run my program using bind. m >>= inst1 >>= inst2
.
Everything works perfectly fine, but I have no idea how to create instruction print
(or read
) in my language with that monad.
I don't want simple, but ugly, solutions like keeping strings to print inside State and printing in main at the end. (What if I have infinity while with print?) I couldn't understand texts from web about that part of monad functionality. There were some explanations like "pack inside IO Monad, it's quite straightforward", but without any working examples. And almost all printing tutorials was about printing in main.
To better explain problem, I prepared minimal "interpreter" example (below). There State
is just Int
, my monad is AutomatM
instructions have type :: Int -> AutomatM Int
. So possible instruction is:
inc :: Int -> AutomatM Int
inc x = return (x+1)
I designed it as simple as I could think:
import Control.Applicative
import Control.Monad (liftM, ap)
import Control.Monad.IO.Class (MonadIO(..))
import System.IO
data AutomatM a = AutomatError | Running a
instance Show a => Show (AutomatM a) where
show (AutomatError) = "AutomatError"
show (Running a) = "Running " ++ show a
instance Functor AutomatM where
fmap = liftM
instance Applicative AutomatM where
pure = return
(<*>) = ap
instance Monad AutomatM where
return x = Running x
m >>= g = case m of
AutomatError -> AutomatError
Running x -> g x
magicPrint x = do
-- print x -- How can I make print work?
-- c <- getLine -- And if that is as simple as print
b <- return "1000" -- how can I change constant to c?
return (x + (read b :: Int))
main = do
a <- getLine
print $ (Running (read a :: Int)) >>= (\x -> return (x*2)) >>= magicPrint
My main target is to add print x
inside magicPrint
. However if it's not harder, it would be nice to have getLine.
I changed state in magicPrint, because print in my language has side effects.
I know that I need something with monad transformers and maybe MonadIO, but it's hard to find any tutorial with simple explanation for beginners. Therefore I would very appreciate extending my minimal code example to work with prints (and maybe getLine/other read Int) and some explanations to that (perhaps with links).
Functor and Aplicative code is based on Defining a new monad in haskell raises no instance for Applicative
IO
in the stack or return some value and then print it. I answered another question about printing in a State monad. Take a look and see if it makes any sense stackoverflow.com/a/50334665/412417 – MCHAFlow (x+1, (print x):olds)
will work? I'm in process of reading above pdf, so maybe it will be clear for me soon. I still don't know how to move your answer to my code. However, I appreciate your effort. – Tacetrb <- getLine
is impossible outside IO monad, same with simple print. Returning likereturn (sequence [a, px], x + (read b :: Int))
wherea
is old IO () and px isprint x
doesn't look like working solution. So I don't know how I should "put on stack IO". Returning values to main is hard, cause I want to print text asap (as interpreter may work very long, and I want to see results as soon as possible). – Tacet