实际上,如果您采用那个答案中提到的 p_sin
不安全的方式,它取决于 p_sin
不是 一种从数字到数字的数学函数——它取决于当相同指针指向的内存不同时给出不同的答案。因此,严格来说,在两次调用之间存在某些不同;通过指针的正式模型,我们可能能够确定这种差异。例如:
type Ptr = Int
type Heap = [Double]
p_sin :: Heap -> Ptr -> Double
而 C 函数将等效于:
p_sin h p = sin (h !! p)
结果不同的原因是由于C定义中未命名但隐含的Heap
参数不同。
如果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
(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
etc.