haskell - FFI 中的可变数据和惰性

标签 haskell vector ffi mutable numerical-computing

介绍

我正在用 inline-c 包装一个 C 数值库;一些函数可以将回调传递给步骤例程,考虑 ODE 的优化或时间积分。

特别是在原生 C 中,使用回调可以对连续数组进行操作,通过指针修改它们,并将它们返回到一些不透明(分布式)数据结构。

所以这是一个可变数据问题,我想在 Haskell 方面表示它:在我的理解中,在回调中我们应该卡住数组,处理它,例如作为 Data.Vector.Storable.Vector 或使用 repa,解卡住果,获取外部指针并将其传回。

内部结构:newtype Vec = Vec (Ptr Vec) deriving Storable,以及 inline-c 上下文中的相关条目,表示指向一个指针的类型不透明的 C 数据结构和 vecGetArray/vecRestoreArray 分别生成/请求指向连续内存的相同指针和请求/生成 Vec

问:

我注意到,虽然返回的 Vector 是正确的,但当我使用经过修改的结果 Vec(“副作用”)时,从该函数返回后,它没有被修改。 GHC 不会重新计算它(懒惰?)。我如何让它重新计算它? Haskell 中有什么惯用的方法来处理 FFI 中的可变数据?


* 固定 *

查看答案


谢谢!

import qualified Data.Vector.Storable as V
import qualified Data.Vector.Storable.Mutable as VM

withVecGetVectorM ::
   Vec ->                                               
   (V.Vector PetscScalar_ -> IO (V.Vector PetscScalar_)) ->   
   IO (V.Vector PetscScalar_)                           
 withVecGetVectorM v f = do 
   p <- vecGetArrayPtr v
   pf <- newForeignPtr_ p
   vImm <- V.freeze (VM.unsafeFromForeignPtr0 pf len)
   vImmOut <- f vImm        
   vMutOut <- V.thaw vImmOut
   let (fpOut, _, _) = VM.unsafeToForeignPtr vMutOut
       pOut = unsafeForeignPtrToPtr fpOut
   vecRestoreArrayPtr v pOut
   return vImmOut
where len = vecSize v

Vec.hs :

vecGetArrayPtr :: Vec -> IO (Ptr PetscScalar_)
vecGetArrayPtr v = chk1 (vecGetArrayPtr' v)

vecRestoreArrayPtr :: Vec -> Ptr PetscScalar_ -> IO ()
vecRestoreArrayPtr v ar = chk0 (vecRestoreArrayPtr' v ar)

内联C.hs

-- PETSC_EXTERN PetscErrorCode VecGetArray(Vec,PetscScalar**);
vecGetArrayPtr' :: Vec -> IO (Ptr PetscScalar_, CInt)
vecGetArrayPtr' v = withPtr $ \p -> vga v p where
  vga v p = [C.exp|int{VecGetArray($(Vec v), $(PetscScalar** p))}|]


-- PETSC_EXTERN PetscErrorCode VecRestoreArray(Vec,PetscScalar**);
vecRestoreArrayPtr' :: Vec -> Ptr PetscScalar_ -> IO CInt
vecRestoreArrayPtr' v c = with c $ \pc -> vra v pc
  where
    vra w pc = [C.exp|int{VecRestoreArray($(Vec w), $(PetscScalar** pc))}|]

此外,IIUC,该代码制作了 2 个额外的矢量副本,一个在卡住时,一个在解冻时。 ,但我怀疑它效率低下。有人可以提出改进或简化建议吗?

最佳答案

固定:

我犯了一个微不足道的错误。要处理的指针;这是解决方法。这个函数与有问题的函数有相同的签名,这表明我必须有一种类型化的方式来表示我们正在修改哪个指针。如果有人对此有任何建议,请随时与我们联系。

vecRestoreVector :: Vec -> V.Vector PetscScalar_ -> IO ()
vecRestoreVector v w = do
  p <- vecGetArrayPtr v
  pf <- newForeignPtr_ p
  V.copy (VM.unsafeFromForeignPtr0 pf len) w
  vecRestoreArrayPtr v p
    where
     len = vecSize v

关于haskell - FFI 中的可变数据和惰性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33418831/

相关文章:

java - 从 Java 中调用 Haskell 函数的最佳方式

haskell - 在下面的示例代码上下文中,如何将函数输出显示为列表 [a],而不是字符串,show [a]

c++ - 将 vector 字符串传递给参数 vector 数组

c++ - 长 double 的加权概率

C 函数将函数作为参数传递,如何使用 node-ffi 包装此函数?

rust - 如何在 Rust 中编写绑定(bind)到需要打开文件句柄的 C 函数?

haskell - 尝试用矩阵编写 Levenshtein 度量的实现

haskell - 这种类型有什么一般结构?

c++ - 从 vector 的 vector 创建一个板

function - 在语言层面, `ccall` 到底是什么?