I have a C function calling into Haskell. The C function passes a StablePtr of a Haskell datatype and the Haskell code needs to change some of its values. What’s an efficient way to do this? For example, consider the following
foreign export ccall editChar :: StablePtr MyObject -> CInt -> CChar -> IO ()
data MyObject = Obj String
editChar :: StablePtr MyObject -> CInt -> CChar -> IO ()
editChar cMyObjectPtr index newChar = do
-- Code goes here
How would editChar be implemented to be as efficient and Haskelly as possible in order to set the Char at index to newChar? Eventually the object being mutated will be rather large memory-wise and have many subcomponents so returning a new object as the result of editChar is out of the question.
You can’t mutate the
Chars insideMyObject. Indeed, you can’t even mutate contents of aStablePtrat all. All you can do is dereference theStablePtrto get yourMyObjectback.If you define
(or
MVarinstead ofIORef)then you’ll be able to mutate it through the usual methods.
For what it’s worth, if memory consumption is what you’re concerned about,
Stringisn’t suitable at all; it uses 5 machine words per character. However, the overhead of “returning a new value” might not be as high as you think: thanks to sharing, prepending aCharto aStringdoesn’t copy the entire string, but instead just reuses the reference to the “old” one. With tree structures such asSeq, these advantages carry over to replacing elements, too.However, if you’re doing a lot of mutation, then you might want to consider a mutable vector.
Of course, if the
Stringis just an example (as your last paragraph implies), then this advice doesn’t necessarily apply. But if you havethen
myHuge { smallPart = 42 }isn’t going to copy the entireGigantic, and ifGiganticis an appropriate tree structure, you’ll be able to do your modifications to it without copying the whole thing. This is the core idea of purely functional, persistent data structures, and one of the most important advantages of Haskell.