有一件事一直困扰着我,那就是现在是否适合使用IORef。在决定是否对任务使用IORef时,有什么应该遵循的指导原则吗?什么时候是使用State monad而不是IORef的好时机?
发布于 2009-12-19 12:40:45
State和它的相关ST都会产生“整体式”有状态计算,这些计算可以作为单元运行。它们基本上将可变状态视为中间数据,这是产生结果所需的,但本身不应该对程序的其余部分感兴趣。
另一方面,人们放在IORef中的并不是要运行的“计算”--它只是一个保存简单值的盒子,可以在IO中以相当任意的方式使用。这个盒子可以放在数据结构中,在程序的IO部分传递,在方便的时候替换它的内容,由函数等关闭。事实上,像C这样的语言中相当多乱七八糟的变量和指针可以用IORefs建模,这为任何希望维护他/她能够用任何语言编写C代码的声誉的专家C程序员提供了很大的帮助。这绝对是需要小心使用的东西。
尽管如此,有时在单个代码块中隔离与一段可变状态的所有交互即使不是完全不可能,也是极其笨拙的--某些状态段必须传递,放在数据结构中等等。在这种情况下,框方法可能是唯一的选择。48小时内给自己写一个方案教程的chapter introducing mutable state (顺便提一下,强烈推荐)提供了一个例子。(请参阅链接,很好地讨论了为什么在方案解释器的特定设计中,使用IORefs来对方案环境建模是最合适的。)
简而言之,这些环境需要以任意的方式嵌套,在用户交互实例之间维护(在Scheme REPL处键入的(define x 1)可能会导致用户稍后能够键入x并返回1作为值),将对象放入建模方案函数中(因为方案函数关闭了创建它们的环境)等。
总而言之,我想说的是,如果一个任务看起来非常适合它,State将倾向于提供最干净的解决方案。如果需要多个独立的状态,也许ST可以提供帮助。但是,如果有状态计算很笨重,或者不可能锁在自己的代码中,状态需要在复杂程序生命周期的很大一部分时间内以可修改的形式持久化等等,那么IORefs可能就是合适的选择。
再说一次,如果需要一种可以通过IO代码传递并以受控方式进行交互的可变状态,为什么不查看STM及其TVars!它们在并发性存在的情况下要好得多,以至于实际上使解决一些与并发性相关的任务变得非常简单。不过,这并不是真的与问题相关,所以我会忍住不去详细说明。:-)
发布于 2009-12-19 12:15:21
嗯。当您需要一些可变状态,但是处于单线程环境中时,您可以使用IORef。或者,当您希望在一个较大的结构中包含一个可变字段时,该结构又由一个同步变量持有。
通常,使用MVars。它们有更健壮的语义。
发布于 2011-11-28 05:52:45
就我个人而言,我会说,只有当你已经在使用IORef的时候,使用IO s是很好的。否则,除非您需要ST的卓越性能,否则请始终使用State。可以在State monad中使用多个状态线程,只需使用一些辅助函数-您只需将状态设置为元组或记录,并定义函数来分别设置、获取或更新每个字段。
特别是,使用StateT s IO通常没有太多意义。如果你已经在IO中,你已经有了可变状态,所以你最好使用它--例如ReaderT (IORef s) IO。
https://stackoverflow.com/questions/1931875
复制相似问题