来自FFI和unsafePerformIO的不可变数据



我正在进行一个到图像加载库的Haskell绑定,我希望尽可能避免复制。当加载图像时,我从包含图像数据的C库中获取数据结构。现在,这个结构在所有意图和目的上都是不可变的,但将数据从中读取到Haskell是一个IO操作。使用unsafePerformIO(或者为了获得更好的性能,可能使用unsafeDupablePerformIO)来避免将内存复制到Haskell数组或类似的数组中,可以吗?当然,我需要将数据结构指针封装在ForeignPtr或类似文件中,并确保指针不能以任何其他方式访问或修改。

在这种情况下,惯例是什么?

如果数据在逻辑上确实是不可变的,那么作为纯函数导入unsafePerformIO或FFI是可以的。unsafePerformIO本质上并不坏,它只是将证明操作是否是引用透明的举证责任从编译器转移到您身上。现在,这实际上是一件棘手且不明显的事情,有时需要证明,所以你为一个很难追踪的大错误引入了一个机会,千万不要因为你无法想象一个错误会假装某个东西是透明的,但并不意味着它是可以的。编译器在利用机会优化事物方面非常聪明。因此,确保你确实证明了不可变的引用透明度,而不仅仅是说服自己,你想不出会出错的方法。但如果你的证据是确凿的,那么你就不应该因为使用它而感到内疚

请注意,当涉及到内存消耗时,这可能会产生后果,不可变的值可能会在未赋值的thunk中保留,并且由于haskell编译器只通过ForeginPtr知道您的对象,因此它不知道保留对象的成本有多高,因此,如果您的不可变对象足够大,使用IO monad的显式生命周期方面对您有用,那么逻辑不变性可能是不够的。类型系统保证正确性,效率是另一回事。

最新更新