yon*_*ong 3 haskell ffi unsafe-perform-io
这是一个后续问题,是否有充分的理由使用unsafePerformIO?
所以我们知道
p_sin(double *p) { return sin(*p); }
Run Code Online (Sandbox Code Playgroud)
不安全,不能用unsafePerformIO
.
但该p_sin
函数仍然是一个数学函数,它以不安全的方式实现的事实是一个实现细节.我们并不完全希望矩阵乘法在IO中,因为它涉及分配临时内存.
我们如何以安全的方式包装这个功能?我们需要锁定,自己分配内存等吗?是否有处理此问题的指南/教程?
实际上,如果你p_sin
从这个答案中加入方式是不安全的,那么它取决于p_sin
不是数学函数,至少不是从数字到数字的函数 - 它取决于当同一指针指向的内存不同时给出不同的答案.所以,从数学上讲,这两个电话之间有一些不同之处; 使用正式的指针模型,我们可能会告诉你.例如
type Ptr = Int
type Heap = [Double]
p_sin :: Heap -> Ptr -> Double
Run Code Online (Sandbox Code Playgroud)
然后C函数相当于
p_sin h p = sin (h !! p)
Run Code Online (Sandbox Code Playgroud)
结果不同的原因是因为一个不同的Heap
参数,它在C定义中是未命名但隐含的.
如果在p_sin
内部使用临时内存,但不依赖于通过其接口的内存状态,例如
double p_sin(double x) {
double* y = (double*)malloc(sizeof(double));
*y = sin(x);
x = *y;
free(y);
return x;
}
Run Code Online (Sandbox Code Playgroud)
那么我们确实有一个实际的数学函数Double -> Double
,我们可以
foreign import ccall safe "p_sin"
p_sin :: Double -> Double
Run Code Online (Sandbox Code Playgroud)
我们没事.界面中的指针在这里杀死纯度,而不是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
Run Code Online (Sandbox Code Playgroud)
等等