什么时候可以使用IORef?

时间:2009-12-19 03:43:31

标签: haskell state monads ioref

让我感到困惑的一件事是,是否可以使用IORef。在决定是否使用IORef执行任务时是否应遵循任何指导原则?何时是使用State monad而非IORef的好时机?

4 个答案:

答案 0 :(得分:73)

状态及其相对ST都产生“单片”状态计算,可以作为单位运行。它们基本上将可变状态视为中间数据,这是生成结果所必需的,但本身不应该对程序的其余部分感兴趣。

另一方面,放在IORef中的不是要运行的“计算” - 它只是一个包含简单值的框,可以在IO中以相当任意的方式使用。这个盒子可以放在数据结构里面,传递给程序的(IO部分),只要它方便就可以替换它的内容,由函数关闭等等。实际上,变量的很多混乱性质和像C这样的语言指针可以用IORefs建模,为任何希望维护他/她能用任何语言编写C代码的声誉的专家C程序员提供很好的帮助......这绝对值得谨慎使用。 / p>

但是,有时非常笨拙,如果不是完全不可能的话,在一个代码块中将所有交互与一段可变状态隔离开 - 某些状态片段必须通过周围,​​放入数据结构等。在这种情况下,盒子方法可能是唯一的选择。 48小时自编一个方案的chapter introducing mutable state教程(强烈推荐,顺便说一下)提供了一个例子。 (请参阅链接,了解为什么最适合使用IORefs而不是State或ST,以便在Scheme解释器的某个设计中为Scheme环境建模。)

简而言之,这些环境需要以任意方式嵌套,在用户交互的实例之间进行维护(在Scheme REPL中键入(define x 1)可能会导致用户以后能够键入{{1}并且返回1作为值),将内部对象建模为Scheme函数(因为Scheme函数在它们创建的环境中关闭)等。

总而言之,我会说,如果一项任务似乎完全适合它,State将倾向于提供最清洁的解决方案。如果需要多个单独的状态,也许ST可以提供帮助。但是,如果有状态计算难以或不可能锁定在自己的代码中,则状态需要在复杂程序的大部分生命周期中以可修改的形式持续存在,然后IORefs可能只是适当的。

然后再次,如果需要那种可以通过IO代码以受控方式传递和交互的可变状态,为什么不检查STM及其TVars!它们在并发性存在的情况下要好得多,事实上,为了使解决一些并发相关的任务变得非常简单。然而,这与问题并没有真正关联,所以我不愿意提出详细说明。 : - )

答案 1 :(得分:14)

嗯。当你需要一些可变状态但是在单线程环境中时,你会使用IORef。或者当你想要一个更大的结构中的可变字段时,该结构又由同步变量保持。

通常,使用MVars。它们具有更强大的语义。

答案 2 :(得分:3)

就我个人而言,我说在时使用IORef并且仅在使用IO时才可以。否则,始终State,除非您需要ST的卓越性能。可以使用具有State monad的多个状态线程,以及一些辅助函数 - 您只需将状态设置为元组或记录,并定义函数以分别设置,获取或更新每个字段。

特别是,使用StateT s IO通常没什么意义。如果您已经在IO,那么您已经拥有可变状态,因此您也可以使用它 - 例如ReaderT (IORef s) IO

答案 3 :(得分:1)

当状态已本地化且不需要与环境交互时,我使用STRef