3

这是对是否有充分的理由使用 unsafePerformIO 的后续问题?

所以我们知道

p_sin(double *p) { return sin(*p); }

不安全,不能与unsafePerformIO.

但该p_sin函数仍然是一个数学函数,它以不安全的方式实现这一事实是一个实现细节。例如,我们并不完全希望矩阵乘法出现在 IO 中,因为它涉及分配临时内存。

我们如何以安全的方式包装这个函数?我们是否需要自己锁定、分配内存等?是否有处理此问题的指南/教程?

4

1 回答 1

6

实际上,如果您合并该p_sin答案不安全的方式,则取决于它p_sin 不是数学函数,至少不是从数字到数字的函数-它取决于当相同指针指向的内存不同时给出不同的答案。因此,从数学上讲,这两个调用之间存在一些不同。有了一个正式的指针模型,我们也许可以知道。例如

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在将其提供给模块用户之前立即进行 ing。这使杂质的表面积最小化。

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

等等

于 2014-08-22T06:34:13.250 回答