如何将解释器带入 IO monad?
How to bring an interpreter to the IO monad?
我的问题与in this answer
中编写的简单解释器有关
如何将 IO 功能添加到 this interpreter(第一个非 monadic 版本)?我的意思只是添加一个使用 putStrLn 的语句。我还不太精通 Haskell,但我猜你可以以某种方式组合 IO monad。有人能给我指出正确的方向吗?
data Stmt
= Var := Exp
| While Exp Stmt
| Seq [Stmt]
| Print Exp -- a print statement
你可以让你的解释器在 IO monad 中有一个结果:
exec :: Stmt -> Store -> IO Store
现在 exec
函数可以在 IO 中做任何事情。现有操作将需要相应修改。
我已经使用 Print 语句扩展了您的解释器,该语句将表达式打印到控制台。 exec 和 运行 的签名必须相应地扩展:
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)]
我的问题与in this answer
中编写的简单解释器有关如何将 IO 功能添加到 this interpreter(第一个非 monadic 版本)?我的意思只是添加一个使用 putStrLn 的语句。我还不太精通 Haskell,但我猜你可以以某种方式组合 IO monad。有人能给我指出正确的方向吗?
data Stmt
= Var := Exp
| While Exp Stmt
| Seq [Stmt]
| Print Exp -- a print statement
你可以让你的解释器在 IO monad 中有一个结果:
exec :: Stmt -> Store -> IO Store
现在 exec
函数可以在 IO 中做任何事情。现有操作将需要相应修改。
我已经使用 Print 语句扩展了您的解释器,该语句将表达式打印到控制台。 exec 和 运行 的签名必须相应地扩展:
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)]