C binding <-> safer haskell API

Hello, I try to create a binding for a C library I can find something like this in the c library merge(HklCube *cube, const HklFrame *frame) So I create a binding with binding-DSL #ccall merge, Ptr <HklCube> -> Ptr <HklFrame> -> IO () Now I want to create a higher level API whcich encode the fact that the cube is modified after the merge. So what is the best way to encode this in the type ? merge :: _ merge c f = do .... c'merge pc pf I thought about IORef, but I am not sure thaht this is the right way to have a safer haskell interface for this method. thanks for your help Fred

On Wed, Feb 09, 2022 at 06:43:39PM +0100, PICCA Frederic-Emmanuel wrote:
So I create a binding with binding-DSL
#ccall merge, Ptr <HklCube> -> Ptr <HklFrame> -> IO ()
Now I want to create a higher level API which encode the fact that the cube is modified after the merge. So what is the best way to encode this in the type?
Perhaps your use-case is somewhat analogous to ByteString, which wraps an underlying (potentially) mutable memory block as an abstract "pure" octet string. With ByteString, operations that produce new bytestrings do so by copying the original buffer (except for "slices" which simply alias part of the buffer content).
merge :: _ merge c f = do .... c'merge pc pf
I thought about IORef, but I am not sure thaht this is the right way to have a safer haskell interface for this method.
Thus the wrapper function would instead have a signature of: merge :: Cube -> Frame -> Cube producing a new Cube, leaving the original unmodified. If however always copying the cube is too expensive, then you can take an approach similar to that used in Array or Vector, where Cubes are available in both immutable and mutable forms, with freeze, thaw, unsafeFreeze and unsafeThaw operations connecting the two. data Cube = Cube ... data STCube s = STCube s ... data IOCube = IOCube ... Mutable cubes can be modified in place in either the IO or ST Monads. -- VIktor.

Hello, I am in this case, the Cube C struct contains at least two realy big arrays. I wan to modify them in place.
If however always copying the cube is too expensive, then you can take an approach similar to that used in Array or Vector, where Cubes are available in both immutable and mutable forms, with freeze, thaw, unsafeFreeze and unsafeThaw operations connecting the two.
data Cube = Cube ... data STCube s = STCube s ... data IOCube = IOCube ...
Mutable cubes can be modified in place in either the IO or ST Monads.
I like this idea, I looked a t the MVector implementation data MVector s a = MVector {-# UNPACK #-} !Int -- ^ Offset in underlying array {-# UNPACK #-} !Int -- ^ Size of slice {-# UNPACK #-} !(MutableArray s a) -- ^ Underlying array deriving ( Typeable ) type IOVector = MVector RealWorld type STVector s = MVector s I imagine that in my case I can can just define a. data MCube s = MCube (ForeignPtr C'HklBinocularsCube) and then type IOCube = NCube RealWorld I a
-- VIktor. _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Sorry I sent the email before finishin it :))
----- PICCA Frederic-Emmanuel
Hello,
I am in this case, the Cube C struct contains at least two realy big arrays. I wan to modify them in place.
If however always copying the cube is too expensive, then you can take an approach similar to that used in Array or Vector, where Cubes are available in both immutable and mutable forms, with freeze, thaw, unsafeFreeze and unsafeThaw operations connecting the two.
data Cube = Cube ... data STCube s = STCube s ... data IOCube = IOCube ...
Mutable cubes can be modified in place in either the IO or ST Monads.
I like this idea, I looked a t the MVector implementation
data MVector s a = MVector {-# UNPACK #-} !Int -- ^ Offset in underlying array {-# UNPACK #-} !Int -- ^ Size of slice {-# UNPACK #-} !(MutableArray s a) -- ^ Underlying array deriving ( Typeable )
type IOVector = MVector RealWorld type STVector s = MVector s
I imagine that in my case I can can just define a.
data MCube s = MCube (ForeignPtr C'HklBinocularsCube)
and then
type IOCube = NCube RealWorld
Then it seems to me that I just need to define a merge function like this merge :: PrimMonad m => MCube (PrimState m) -> Frame -> m () and then an unsafeFreeze to avoid copy. It that correct ? Cheers Fred

On Thu, Feb 10, 2022 at 10:39:26AM +0100, PICCA Frederic-Emmanuel wrote:
Then it seems to me that I just need to define a merge function like this
merge :: PrimMonad m => MCube (PrimState m) -> Frame -> m ()
and then an unsafeFreeze to avoid copy. It that correct?
Well, the `unsafeFreeze` would typicall only be appropriate in pure functions that *construct* a pure `Cube` from scratch by allocating and mutating an `MCube`. As for merge itself, it runs in IO and mutates an `MCube`. It is the caller's responsibility to ensure that that object is not "shared". If the entire computation runs in `IO` then you just use MCube(s) throughout. Once you have a pure `Cube`, you would typically not mutate it in place, except in "linear" use-cases that *consume* its *sole* reference while mutating it in place (possibly returning a fresh Cube based on the modified copy). Ensuring "linearity" is not trivial (a key reason for the existence of "Rust"). Use of `unsafeThaw` is atypical. -- Viktor.
participants (2)
-
PICCA Frederic-Emmanuel
-
Viktor Dukhovni