这是Is there ever a good reason to use unsafePerformIO?
的后续问题所以我们知道
p_sin(double *p) { return sin(*p); }
不安全,不能与unsafePerformIO
一起使用。
但是p_sin
函数仍然是一个数学函数,它以不安全的方式实现的事实是一个实现细节。我们并不完全希望矩阵乘法在IO中,因为它涉及分配临时内存。
我们如何以安全的方式包装此功能?我们需要锁定,自己分配内存等吗?是否有处理此问题的指南/教程?
答案 0 :(得分:6)
实际上,如果你采用p_sin
对该答案不安全的方式,它取决于p_sin
而不是是一个数学函数,至少不是一个从数字到数字 - 当相同指针指向的内存不同时,它取决于给出不同的答案。所以,从数学上讲,两个调用之间存在某种的不同;使用正式的指针模型,我们可能会告诉你。 E.g。
type Ptr = Int
type Heap = [Double]
p_sin :: Heap -> Ptr -> Double
然后C函数等同于
p_sin h p = sin (h !! p)
结果不同的原因是因为一个不同的Heap
参数,它在C定义中是未命名但隐含的。
如果p_sin
在内部使用临时内存,但不依赖于通过其接口的内存状态,例如
double p_sin(double x) {
double* y = (double*)malloc(sizeof(double));
*y = sin(x);
x = *y;
free(y);
return x;
}
然后我们确实有一个实际的数学函数Double -> Double
,我们可以
foreign import ccall safe "p_sin"
p_sin :: Double -> Double
我们没事。界面中的指针在这里杀死纯度,而不是C函数。
更实际的是,我们假设你有一个用指针实现的C矩阵乘法函数,因为那是你在C中对数组建模的方法。在这种情况下,你可能会扩展抽象边界,所以在你的程序中会发生一些不安全的事情,但它们都会被模块用户隐藏起来。在这种情况下,我建议在实现中使用IO
注释所有不安全的内容,然后在将unsafePerformIO
提供给模块用户之前将其module Matrix
-- only export things guaranteed to interact together purely
(Matrix, makeMatrix, multMatrix)
where
newtype Matrix = Matrix (Ptr Double)
makeMatrix :: [[Double]] -> Matrix
makeMatrix = unsafePerformIO $ ...
foreign import ccall safe "multMatrix"
multMatrix_ :: Ptr Double -> IO (Ptr Double)
multMatrix :: Matrix -> Matrix
multMatrix (Matrix p) = unsafePerformIO $ multMatrix_ p
注释掉。这样可以最大限度地减少杂质的表面积。
{{1}}
等