I'm writing bindings (for the first time). On C level there are function to allocate some sort of resource, let's call it ParentRes
. It returns IO (Ptr ParentRes)
. Everytime ParentRes
is created, a child resource allocated, let's call it ChildRes
. This stuff is all static, child pointer cannot change and it's freed when parent resource is freed.
Now the catch: there is a function that takes pointer to parent and returns pointer to child:
foreign import ccall unsafe "…"
c_get_child_res :: Ptr ParentRes -> IO (Ptr ChildRes)
I want to write wrapper of type Ptr ParentRes -> Ptr ChildRes
using unsafePerformIO
. Is there a reason I should not do it?
Here I'm answering from my real experience that I have had just now because of “pure” functions that are not quite pure.
I can formulate it in these words: everything that can be affected by order
of execution should always stay in IO
. IO
monad is Haskell is standard
and reliable way to ensure order of execution. If order matters, your
functions should live in IO
monad.
Now, if it's not obvious why order matters in this particular case, remember
than parent resource as well as child resource must be allocated and then
they are freed. When they are freed you won't get the same results (but
rather segmentation fault), so referential transparency is broken. So these
resource-dependent functions should stay in IO
.
Also, I don't think it's impossible to allocate different objects at the same address during single program execution. This again would break referential transparency.