【问题标题】:How does readIORef work: creates copy or it does not?readIORef 是如何工作的:创建副本还是不创建?
【发布时间】:2019-08-14 07:16:48
【问题描述】:

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

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

【问题讨论】:

    标签: haskell immutability io-monad do-notation ioref


    【解决方案1】:

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

    IORef 包含一个值。 IORef 本身是可变的:您可以更改它包含的值。值本身是不可变的。要理解这一点,请考虑当前包含 5IORef Int。如果你把那个值加一个得到6,你已经创建了一个新值,但是你没有把5的值突然变成6,因为5的值是不可变的.

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

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

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

    【讨论】:

    • 是的,当然是这样,但问题是:如果我的线程 A 用readIORef 读取地图并且我正在用它做一些事情,它可以被另一个线程 B 更改吗?据我所知,Haskell 写时复制,IO monad 也只是旧的类似 C 代码的包装器(readIORef/writeIORef 甚至可以像在 C 中一样重新排序),所以:someMap 可以在我阅读后被另一个线程更改是吗?
    • @Paul-AG:不,因为如果你使用writeIORef,你会在引用中写入不同的值。数据结构永远不会被修改,您创建一个“浅”的修改副本。因此,如果您写信给IORef,则意味着您现在让 ref 指向不同的地图。
    • @Paul-AG 我认为您正试图通过了解 Haskell 如何将其转换为内存上的低级操作来理解它的语义。这适用于 C 或 C++ 甚至 Java 等命令式语言,因为这些语言的底层程序员模型是冯诺依曼架构。它不适用于 Haskell,因为 Haskell 的底层程序员模型是 lambda 演算。因此,您应该停止尝试从指针和副本的角度来考虑 Haskell 语义,而应该尝试从值和函数的角度来考虑。
    • 虽然这种特殊情况很容易通过指针和副本的类比来解释。一个 IORef 我想要一个包含指向不可变对象的指针的可变变量。读取指针是原子的,因此另一个线程不可能在我正在读取它的“同时”写入指针。一旦我阅读了它以找出所指向的对象,其他线程做什么都无关紧要。它们无法更改我现在正在使用的不可变对象,因此只有在我再次读取指针时它们才会影响我。
    【解决方案2】:

    readIORef :: IORef a -&gt; IO a,所以myMap 必须是IORef areadIORef myMap :: IO a

    所以someMap :: a,因为它在do 类型IO a 的代码行中&lt;- 的左侧(它始终是a &lt;- M a,在do 表示法中)。

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2012-07-16
      • 1970-01-01
      • 2018-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-28
      • 1970-01-01
      相关资源
      最近更新 更多