什么时候可以使用IORef?

有一件事让我困惑不已,那就是现在是否可以使用IORef。 在决定是否使用IORef来执行任务时,是否有任何指导原则? 什么时候在IORef上使用State Monad?

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

另一方面,在IORef中放入的内容不是一个要运行的“计算” – 它只是一个盒子,它具有一个简单的值,可以在IO内以相当任意的方式使用。 这个方块可以放在数据结构里面,传递给程序的(IO部分),每当方便的时候都replace它的内容,被函数等closures。事实上,variables和像C这样的语言指针可以用IORefsbuild模,为任何希望维护他/她能够用任何语言编写C代码的专家的C程序员提供了很大的帮助…这是一定要谨慎使用的东西。

尽pipe如此,如果不是完全不可能的话,在单个代码块中用一个可变状态隔离所有的交互有时是极其笨拙的 – 一些状态片段必须被传递,放到数据结构中等等。箱子的方式可能是唯一的select。 在48小时教程中介绍写自己的计划的可变状态章节 (强烈推荐,顺便说一下)提供了一个例子。 (请参阅链接,了解为什么使用IORefs(而不是State或ST)来为Scheme解释器的特定devise中的Scheme环境build模是非常合适的)。

简而言之,这些环境需要以任意方式嵌套,在用户交互的实例之间维护(在Scheme REPL中键入的(define x 1)应该可能导致用户稍后能够键入x并返回1作为值),放入对象build模Scheme函数(因为Scheme函数closures它们创build的环境)等

总而言之,如果一项任务似乎完全适合它,国家将倾向于提供最干净的解决scheme。 如果需要多个独立的状态,或许ST可以提供帮助。 但是,如果有状态的计算在自己的代码中难以locking或不可能locking,那么状态就需要在复杂程序的大部分生命周期中坚持可修改的forms,那么IORefs可能就是适当的东西。

然后再一次,如果需要一种可以通过IO代码以可控方式传递和交互的可变状态,为什么不检查STM和它的TVars呢? 在并发的情况下,它们更好,事实上,解决一些与并发有关的任务实际上很简单。 但是,这并不是真的与这个问题有关,所以我会拒绝详细说明。 🙂

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

一般来说,使用MVars。 他们有更强大的语义。

就我个人而言, 你使用IO,只要使用IORef就可以。 否则,总是State ,除非你需要ST的优越性能。 使用状态monad可以使用多个状态线程,只需要一些辅助函数 – 只需使状态成为元组或logging,然后定义函数来分别设置,获取或更新每个字段。

特别是,使用StateT s IO通常没有多less意义。 如果你已经在IO ,你已经有了可变状态,所以你可以使用它 – ReaderT (IORef s) IO

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