IO 中的就地更新

In-place update in IO

是否有(低级)GHC 功能允许就地更新 IORef 中的特定 constructor/record 字段以提高效率?

给定以下代码:

data Object = Object {
    field1 :: Int
    field2 :: VeryLargeDataType
    }

main :: IO ()
main = do
    var <- newIORef
    writeIORef var $ Object {
             field1 = 42,
             field2 = lotsOfData
        }
    modifyIORef var (\a -> a { field1 = (field1 a + 1) } )
    ...

GHC 将读出非常大的对象,执行微不足道的修改,然后将其写回。

理论上,只对字段进行就地更新就足够了,而且效率更高。

有没有 GHC 功能,例如一个低级原语,可以让我为 any ADT?

我知道特殊情况的解决方案是创建其他字段 IORef 而不是结构,但我正在寻找一种方法来对任何结构(包括来自库的结构)执行此操作。

没有这样的功能。它通常也不安全:就地修改那个大对象意味着之前从引用中读取的任何人现在都将具有与以前不同的值。 (当然可能存在安全的受限情况。但我敢打赌,这种情况比您猜测的要少。)

您可能也有兴趣阅读或注册 this language proposal 的更新。

目前无法做到这一点 (GHC 8.10.3)。

不过好在 Haskell 中的大部分内容都保留为参考,因此 lotsOfData 根本不会 被复制(指针将是,但 8 个字节应该可以复制)。因此,您的代码应该是高性能的。

我会重构 Object 甚至 VeryLargeDataType 以包含 IORef,但只有在绝对必要时,即只有在我用尽所有其他优化选项之后。

但是 - 当然 - 只有您可以控制该类型才有可能,例如它不是来自图书馆。

好消息是 Haskell 中每天使用的数据结构通常具有合理的性能。 (一个著名的例子当然是列表。)包通常会记录其功能的复杂性,因此您可以提前计划。