问题
My question relates to the simple interpreter written in in this answer
How could one add IO capabilities to this interpreter (the first non monadic version)? By this I simply mean adding a statement that uses putStrLn. I'm not that well versed in Haskell yet, but I'm guessing you can just combine the IO monad somehow. Can somebody point me in the right direction?
data Stmt
= Var := Exp
| While Exp Stmt
| Seq [Stmt]
| Print Exp -- a print statement
回答1:
You can make your interpreter have a result in the IO monad:
exec :: Stmt -> Store -> IO Store
Now the exec
function can do anything in IO. The existing operations will need to be modified accordingly.
回答2:
I have extended your interpreter with a Print statement that prints an expression to the console. the signature of exec and run had to be extended accordingly:
infixl 6 :+:, :-:
infixl 7 :*:, :/:
data Exp
= C Int -- constant
| V Var -- variable
| Exp :+: Exp -- addition
| Exp :-: Exp -- subtraction
| Exp :*: Exp -- multiplication
| Exp :/: Exp -- division
deriving (Show)
infix 1 :=
data Stmt
= Var := Exp -- assignment
| While Exp Stmt -- loop
| Seq [Stmt] -- sequence
| Print Exp
type Prog = Stmt
type Var = String
type Val = Int
type Store = [(Var, Val)]
eval :: Exp -> Store -> Val
eval (C n) r = n
eval (V x) r = case lookup x r of
Nothing -> error ("unbound variable `" ++ x ++ "'")
Just v -> v
eval (e1 :+: e2) r = eval e1 r + eval e2 r
eval (e1 :-: e2) r = eval e1 r - eval e2 r
eval (e1 :*: e2) r = eval e1 r * eval e2 r
eval (e1 :/: e2) r = eval e1 r `div` eval e2 r
exec :: Stmt -> Store -> IO Store
exec (x := e) r = return $ (x, eval e r) : r
exec (While e s) r | eval e r /= 0 = exec (Seq [s, While e s]) r
| otherwise = return r
exec (Seq []) r = return r
exec (Seq (s : ss)) r = do
r' <- exec s r
exec (Seq ss) r'
exec (Print x) r = print (eval x r) >> return r
run :: Prog -> Store -> IO Store
run p r = nubBy ((==) `on` fst) <$> (exec p r)
fib :: Prog
fib = Seq
[ "x" := C 0
, "y" := C 1
, While (V "n") $ Seq
[ "z" := V "x" :+: V "y"
, "x" := V "y"
, "y" := V "z"
, "n" := V "n" :-: C 1
, Print (V "x")
]
]
main = lookup "x" <$> run fib [("n", 25)]
来源:https://stackoverflow.com/questions/53994496/how-to-bring-an-interpreter-to-the-io-monad