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 inside MyObject. Indeed, you can't even mutate contents of a StablePtr at all. All you can do is dereference the StablePtr to get your MyObject back.
If you define
newtype MyObject = Obj (IORef String)
(or MVar instead of IORef)
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, String isn'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 a Char to a String doesn't copy the entire string, but instead just reuses the reference to the "old" one. With tree structures such as Seq, 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 String is just an example (as your last paragraph implies), then this advice doesn't necessarily apply. But if you have
data Huge = Huge { giganticPart :: Gigantic, smallPart :: Int }
then myHuge { smallPart = 42 } isn't going to copy the entire Gigantic, and if Gigantic is 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With