我想知道在哈斯克尔是否有合法的使用IORef?更具体地说,如果有人能回答以下问题或指出一个适当的地方了解更多这方面的情况,我将非常感激:
我正在阅读一篇使用IORef作为代码片段的论文,由于我对IORef的负面看法,它对我来说一直很难阅读。与其沉溺于我的无知之中,我认为向哈斯克勒同胞寻求帮助也许是个更好的主意。
发布于 2018-09-23 20:12:59
首先,我认为对于论文中的代码片段来说,使用IORef是非常明智的,特别是如果本文不是关于可变引用或并发的最佳实践的话。IORef很容易理解,语法和语义都很简单(特别是在非并发设置中),如果您希望读者专注于IORef以外的示例,这是一种自然的选择。不幸的是,作者的方法对您来说适得其反--只需忽略IORef,关注论文的其余内容。
(如果这篇论文是关于可变引用或并发性的最佳实践的话,那么它也许是在获得更好的替代方案之前编写的。)
无论如何,对于您更大的问题,使用IORef的主要反对意见是:
STRef RealWorld的新类型包装器,它在STRef上添加的唯一东西就是一些原子操作。在非并发代码中,没有充分的理由不在ST s monad中使用ST s值,因为它们更灵活--您可以使用runST运行它们,如果需要,也可以在带有stToIO的IO monad中运行它们。MVar和STM,它们比IORef的更容易使用。因此,在可变状态是“坏”的程度上--如果您真的需要它--根据您是否需要并发性,可以获得更好的替代方案,因此没有什么可推荐的IORef。
另一方面,, --如果您已经在IO monad中处理一些非并发代码,因为您需要执行实际的IO操作,并且您确实需要一些不容易与IO分离的普遍的可变状态,那么使用IORef似乎是合法的。
关于你更具体的问题:
IORef时,weaker tool would do the job被认为是“不好的实践”。这个较弱的工具可能是一个STRef s,或者更好的是一个State单块,或者更好的一个重写的高阶算法,它根本不需要任何状态。因为IORef将IO与可变引用结合在一起,这是一种命令式的大锤,可能会导致最统一的Haskell代码,因此,除非它“显然”是解决特定问题的正确解决方案,否则最好避免它。State monad通常是向程序添加状态的首选惯用方法,但它通过通过计算线程处理一系列不变的状态值来提供可变状态的“错觉”,而且并不是所有的算法都能以这种方式有效地实现。当需要真正的可变状态时,STRef通常是非并发设置中的自然选择。请注意,您可能不会在非并发设置中使用MVar或STM --在本例中没有使用它们的理由,而且即使您不需要它们,它们也会强迫您进入IO monad。IORef或STRef都优于State、STM、MVar或纯IO (见下文)。有几种情况下,IORef显然比STRef更可取,但是--正如上面提到的--如果您已经处于IO monad中,并且需要与IO操作纠缠在一起的真正的可变状态,那么IORef在语法上可能比STRef有优势。一些例子说明了IORef或STRef是一种很好的方法:
Data.Unique在base包中使用IORef作为生成唯一对象的全局计数器。base库中,文件句柄内部广泛使用IORefs将缓冲区附加到句柄。这是一个很好的例子,“已经在IO单与纠缠的IO操作”。vector包的可变向量,那么从技术上讲,您使用的是可变字节数组,而不是STRef或IORef,但在道义上仍然是等价的。equivalence包使用STRefs来高效地实现联合连接算法。IORef或STRef值通常是最有效的。https://stackoverflow.com/questions/52467957
复制相似问题