3

はじめに

inline-cC 数値ライブラリを;でラップしています。一部の関数はステップ ルーチンにコールバックを渡すことができます。ODE の最適化または時間積分を考えてみてください。

特にネイティブ C の使用では、コールバックは連続した配列を操作し、ポインターを介してそれらを変更し、不透明な (分散された) データ構造にそれらを返すことができます。

したがって、これは変更可能なデータの問題であり、Haskell 側で表現したいと思います。私の理解では、コールバックで配列をフリーズし、たとえば aData.Vector.Storable.Vectorまたは withとして作業しrepa、結果を解凍し、外部ポインタを取得する必要があります。そしてそれを返します。

internals: newtype Vec = Vec (Ptr Vec) deriving Storable、およびinline-cContext 内の関連するエントリは、不透明な C データ構造へのポインタの型を表し、vecGetArray/vecRestoreArray隣接メモリへの同じポインタを生成/要求し、 を要求/生成しVecます。

Q:

Vector返されたものは正しいのですがVec、この関数から戻った後に変更された結果 (「副作用」) を使用すると、変更されていないことに気付きました。GHC はそれを再計算しません (怠惰?)。再計算するにはどうすればよいですか?FFI全体で変更可能なデータを操作するために、Haskellにはどのような慣用的な方法がありますか?


* 修理済み *

答えを見る


ありがとう!

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 つの追加のコピーを作成します。1 つは凍結時、もう 1 つは解凍時です。、しかし、それは非効率的だと思います。誰かが改善や簡素化を提案できますか?

4

1 に答える 1

0

修理済み:

私は些細な間違いを犯していました。処理するポインター。これが修正です。この関数は、バグのある関数と同じシグネチャを持っています。これは、どのポインタを変更しているかを示すタイプフルな方法が必要であることを示唆しています。これに関して提案がある場合は、遠慮なく連絡してください。

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
于 2015-10-30T15:47:33.410 に答える