FFI 中的可变数据和懒惰

Mutable data across the FFI and laziness

提问人:ocramz 提问时间:10/29/2015 最后编辑:ocramz 更新时间:10/31/2015 访问量:204

问:

介绍

我正在用 ;一些函数可以回调到步进例程、偏微分方程的优化或时间积分。inline-c

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

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

internals: 和 Context 中的关联条目分别表示指向不透明 C 数据结构的指针的类型和/生成/请求指向连续内存的相同指针和请求/生成 。newtype Vec = Vec (Ptr Vec) deriving Storableinline-cvecGetArrayvecRestoreArrayVec

Q:

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


*固定*

查看答案


谢谢!

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)

InlineC.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 个额外的载体副本,一个在冻结时,一个在解冻时。,但我怀疑它效率低下。有人可以提出改进或简化建议吗?

哈斯克尔 向量 FFI公司 可变 数值计算

评论

0赞 user2407038 10/30/2015
您类型中的指针似乎由 更新。此函数中可能存在错误,因此您也应该包含它。VecvecRestoreArrayPtr
0赞 ocramz 10/30/2015
谢谢用户2407038 , 编辑
1赞 user2407038 10/30/2015
此外,您可以通过替换为 来删除副本,这不会创建副本。我认为这应该是安全的,因为无论如何你都会用计算结果覆盖你的。但是,如果发生异常,您可能会处于不一致的状态 - 最好还是将其复制过来。thawunsafeThawVec

答:

0赞 ocramz 10/30/2015 #1

固定:

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

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