Haskell readIORef如何工作:创建副本还是不创建副本?
这段代码到底是做什么的?Haskell readIORef如何工作:创建副本还是不创建副本?,haskell,immutability,io-monad,do-notation,ioref,Haskell,Immutability,Io Monad,Do Notation,Ioref,这段代码到底是做什么的?someMap是myMap引用的对象(属于::Data.Map.Strict.Map)的副本还是仅作为参考?我的意思是,在我用readIORef阅读后,是否可以someMap更改(通过另一个线程)?有点像C的挥发性。。。可能吗?我希望它是复制/快照,所以任何更改都不会影响我的someMap,或者 do .... someMap不,它不是副本。在Haskell中没有“复制”这类东西,只有值,所有值都是不可变的 IORef包含一个值。IORef本身是可变的:您可以更改它包含的
someMap
是myMap
引用的对象(属于::Data.Map.Strict.Map
)的副本还是仅作为参考?我的意思是,在我用readIORef
阅读后,是否可以someMap
更改(通过另一个线程)?有点像C的挥发性。。。可能吗?我希望它是复制/快照,所以任何更改都不会影响我的someMap
,或者
do
....
someMap不,它不是副本。在Haskell中没有“复制”这类东西,只有值,所有值都是不可变的
IORef
包含一个值。IORef
本身是可变的:您可以更改它包含的值。值本身是不可变的。要理解这一点,请考虑一个当前包含5
的IORef Int
。如果您将该值取出并添加一个值以获得6
,您已经创建了一个新值,但是您没有将5
值更改为突然变为6
,因为5
的值是不可变的
同样,如果我用值fromList[(“foo”,5),(“bar,6”)]
创建一个Map
,并将其放入IORef中,IORef现在包含该值,但该值本身是不可变的。如果我取出值并使用Map.insert添加一个新条目,我创建了一个新值,而不是修改原始值,方法与上面的5
和6
完全相同
希望这能回答你的问题。不过,您现在可能有另一个。如果所有值都是不可变的,IORefs如何更改
答案是IORef本身不会改变。然而,IOREF是一种通向我们称之为“真实世界”的变化无常的混乱的门户。在现实世界中,你可以做同样的事情两次,得到不同的结果。这包括readLine
和readIORef
。IO单子的存在是为了隔离这种混乱,同时仍然允许程序与之交互。因此,使用IORefs的每个函数都在IO单子中。readIORef::IORef a->IO a
,因此myMap
必须是IORef a
和readIORef myMap::IO a
所以someMap::a
,因为它在的左边是的,当然是这样,但问题是:如果我的线程a使用readIORef
读取映射,并且我正在使用它做一些事情,那么它能被另一个线程B更改吗?据我所知,Haskell在编写时会进行复制,而且IO monad是好的类C代码的唯一包装器(readIORef/WriteOref甚至可以像C中一样重新排序),因此:someMap
可以在我读过它之后被另一个线程更改吗?@Paul AG:不,因为如果使用WriteOref
,您会向引用写入不同的值。数据结构永远不会被修改,您将创建一个“浅”修改副本。因此,如果您写入IORef
,则意味着您现在让ref指向一个不同的映射。@Paul AG我认为您试图通过理解Haskell如何转换为内存上的低级操作来理解它的语义。这对于命令式语言(如C语言或C++语言,甚至java)都适用,因为这些语言的底层程序员模型是冯诺依曼体系结构。它不适用于Haskell,因为Haskell的底层程序员模型是lambda演算。因此,你不应该试图从指针和副本的角度来思考Haskell语义,而应该试着从值和函数的角度来思考。尽管这个特殊的例子很容易用指针和副本的类比来解释。IORef我想要一个包含指向不可变对象指针的可变变量。读取指针是原子性的,所以当我读取指针时,另一个线程不可能写入指针。一旦我阅读了它以找出指向的对象,其他线程做什么并不重要;它们无法更改我现在使用的不可变对象,因此它们只能在我再次读取指针时影响我。