如何将 monadic 解释器引入 IO monad?

How to bring a monadic interpreter to the IO monad?

我的问题涉及in this answer. I already asked a 中编写的简单解释器,它涉及link后面的答案中的第一个非单子解释器。但是有一个第二个单子,与这个问题相关。

如何向 the monadic interpreter 添加 IO 功能(您需要向下滚动 因为答案包含两个变体,第一个是非单子的,second monadic.)?我的意思只是添加一个使用 putStrLn 的语句。我还不太精通 Haskell,但我猜你可以以某种方式将 IO monad 与解释器 monad 结合起来。有人能给我指出正确的方向吗?

data Stmt
  = Var := Exp                                   
  | While Exp Stmt                                               
  | Seq [Stmt]      
  | Print Exp       -- a print statement

一种直接的方法是更改​​ Interp 以合并 IO

newtype Interp a = Interp { runInterp :: Store -> IO (Either String (a, Store)) }

然后我们只需要更新 Monad 实例、rdwrrun 以获取 Interp 的新内部结构一些 returns 和绑定。例如,这是新的 Monad 实例:

instance Monad Interp where
  return x = Interp $ \r -> return (Right (x, r))
  i >>= k =
    Interp $ \r -> do
      res <- runInterp i r
      case res of
        Left msg -> return (Left msg)
        Right (x, r') -> runInterp (k x) r'
  fail msg = Interp $ \_ -> return (Left msg)

首先抽象出 Interp 的一个优点是我们可以在不修改解释器的主要部分(evalexec) 完全没有。