readIORef如何工作:创建副本还是不创建副本?

Pau*_*-AG 2 haskell immutability do-notation io-monad ioref

该代码的作用是什么?是someMap(的::Data.Map.Strict.Map)对象的副本是否由myMap引用或仅作为引用?我的意思是在我阅读后可以someMap更改(通过另一个线程)readIORef吗?像C的易失性...可能吗?我希望它是复制/快照,因此任何更改都不会影响我someMap或...?

     do
        ....
        someMap <- readIORef myMap
        ....
Run Code Online (Sandbox Code Playgroud)

Pau*_*son 5

不,它不是副本。在Haskell中,没有“复制”之类的东西,只有值,并且所有值都是不可变的。

一个IORef包含一个值。在IORef本身是可变的:你可以改变的价值在于它包含的内容。该值本身是不可变的。要了解这一点,请考虑IORef Int当前包含的5。如果您获得该值并添加一个6值,则可以创建一个新值,但尚未更改该5值突然变为6,因为的值5是不变的。

同样,如果我Map使用该值创建一个fromList [("foo", 5), ("bar, 6")]并将其放入IORef中,则IORef现在包含该值,但是该值本身是不可变的。如果我得到该值并使用Map.insert创建的新值(未修改原始值)添加新条目,则与56上面的方法完全相同。

希望能回答您的问题。但是,您现在可能会有另一个。如果所有值都是不可变的,则IORefs如何更改?

答案是IORef本身不会改变。但是,IORef可以作为通向不断变化的,我们称为“现实世界”的混乱状态的门户。在“现实世界”中,您可以两次执行相同的操作并获得不同的结果。其中包括readLinereadIORef。存在IO monad可以隔离此混乱情况,同时仍允许程序与其进行交互。因此,与IORefs兼容的每个功能都在IO monad中。

  • 尽管通过指针和副本的类比很容易解释这种特殊情况。IORef我想要一个可变变量,其中包含一个指向不可变对象的指针。读取指针是原子的,因此另一个线程不可能在我正在读取的同时“写入”指针。一旦阅读了它以找出所指向的对象,其他线程的作用就无关紧要了。它们无法更改我现在正在使用的不可变对象,因此它们只有在我再次读取指针时才会影响我。 (4认同)
  • @ Paul-AG我想您正在通过了解Haskell如何将其转换为对内存的低级操作来理解其语义。这适用于命令式语言,如C或C ++,甚至Java,因为这些语言的基础程序员模型是冯·诺依曼体系结构。它对Haskell不起作用,因为Haskell的基础程序员模型是lambda演算。因此,您应该停止尝试根据指针和副本来考虑Haskell语义,而应该尝试根据值和函数来进行思考。 (3认同)
  • @ Paul-AG:否,因为如果使用`writeIORef`,则会向引用写入不同的值。数据结构永远不会被修改,您将创建一个“浅”的修改副本。因此,如果您写入“ IORef”,则意味着您现在让ref指向其他地图。 (2认同)