2

这段代码究竟做了什么?someMap对象 (of ::Data.Map.Strict.Map) 的副本是由引用myMap还是仅作为引用?我的意思是在我阅读后可以someMap改变(通过另一个线程)readIORef?像 C 的 volatile 之类的东西……有可能吗?我希望它是复制/快照,因此任何更改都不会影响我的someMap, 或 ...?

     do
        ....
        someMap <- readIORef myMap
        ....
4

2 回答 2

5

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

AnIORef包含一个值。它IORef本身是可变的:您可以更改它包含的值。值本身是不可变的。要理解这一点,请考虑IORef Int当前包含5. 如果您取出该值并将其添加一个以使6您创建了一个新值,但您并没有将5值更改为突然变为6,因为 的值5是不可变的。

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

希望这能回答你的问题。但是,您现在可能有另一个。如果所有值都是不可变的,那么 IORefs 怎么会改变呢?

答案是 IORef 本身不会改变。然而,IORef 是作为一种通往我们称之为“真实世界”的可变的、不断变化的混乱的门户而存在的。在真实世界中,你可以做同样的事情两次,得到不同的结果。这包括readLinereadIORef。IO monad 的存在是为了隔离这种混乱,同时仍然允许程序与之交互。因此,与 IORefs 一起工作的每个函数都在 IO monad 中。

于 2019-08-14T07:35:48.980 回答
2

readIORef :: IORef a -> IO a,所以myMap必须是IORef areadIORef myMap :: IO a

所以someMap :: a,因为它在类型<-do代码行的左边IO a(它a <- M a总是在do符号中)。

在您的情况下, that a ~ Data.Map.Strict.Map k v,即纯粹的不可变值。

如果另一个线程将一些新值写入 that myMap :: IORef (Data.Map.Strict.Map k v),那么它会这样做。但它不会改变在转换之前已经从中提取的纯值。

有效的代码有时间。具有不可变数据的纯引用透明代码是永恒的。

(什么是真的,就是真的,不管需要多长时间来证明它。)

于 2019-08-14T11:00:08.623 回答