Haskell 如何将一元解释器带到IO monad?

Haskell 如何将一元解释器带到IO monad?,haskell,interpreter,Haskell,Interpreter,我的问题是关于用英语写的简单翻译。我已经问了a,这与链接后面的答案中的第一个非一元翻译有关。但是有一个第二个一元的,这个问题与之相关 如何将IO功能添加到(您需要向下滚动,因为答案包含两种变体,第一种是非一元变量,第二种是一元变量)?我的意思是添加一个使用putStrLn的语句。我还不太精通Haskell,但我猜你可以把IO单子和解释器单子结合起来。谁能给我指一下正确的方向吗 data Stmt = Var := Exp

我的问题是关于用英语写的简单翻译。我已经问了a,这与链接后面的答案中的第一个非一元翻译有关。但是有一个第二个一元的,这个问题与之相关

如何将IO功能添加到(您需要向下滚动,因为答案包含两种变体,第一种是非一元变量,第二种是一元变量)?我的意思是添加一个使用putStrLn的语句。我还不太精通Haskell,但我猜你可以把IO单子和解释器单子结合起来。谁能给我指一下正确的方向吗

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

一种简单的方法是将
Interp
更改为包含
IO

newtype Interp a=Interp{runInterp::Store->IO(字符串(a,Store))}
然后,我们只需要更新
Monad
实例、
rd
wr
、和
run
,通过添加一些
return
和binds来更新
Interp
的新内部结构。例如,下面是新的
Monad
实例:

实例Monad Interp其中
return x=Interp$\r->return(右(x,r))
i>>=k=
Interp$\r->do
res返回(左消息)
右(x,r')->runInterp(kx)r'
失败消息=Interp$\\->返回(左消息)

首先抽象出
Interp
的一个好处是,我们可以在不修改解释器的主要部分(
eval
exec
)的情况下进行这些更改。

您为什么要问这两次?(你似乎已经接受了上一个答案。)可能是重复的,不是我写的吗?第一个问题和它被接受的答案与非一元语法分析器有关,而这一个与一元语法分析器有关。除了IO单子,您可能需要使用Writer单子。然后你可以对结果做任何你想做的事情,比如印刷。@Robin Zigmond:如果有人能提供建设性的评论,那就太好了。我希望我的编辑清楚地表明,这不是同一个问题,我也在寻找这个问题的答案,而不仅仅是另一个问题的答案。我是否应该创建一个新的问题,将一元语法分析器复制到其中,并询问如何添加打印语句?我一直在阅读有关monad transformers的文章,同时试图解决这个问题。你认为那样做有意义吗?看起来(对我这个没有经验的读者来说),这实际上可以让我在同一个解释器monad中使用不同的monad,用于不同的目的(比如读写器),而不是仅仅公开整个IO。当然,你可以在这里使用monad转换器。例如,
newtype Interp m a=Interp{runInterp::Store->m(字符串(a,Store))}
(使用
m
而不是
IO
)是一个monad转换器。您可以将
字符串
部分作为
EitherT
,将
(,Store)
部分作为
WriterT
。这取决于你想在这条道路上走多远。用越来越复杂的抽象来概括你的程序的能力是Haskell最大的优点之一,也是Haskell最大的缺点之一……你为什么要用
WriterT
来代替
(,Store)
?是不是
Store
更像一个
StateT
?@JohnSmith你说得对,这就是我应该写的。