allocation for "pure" FFI functions

Hi. I wonder how to do the following properly. I have one (large) C type, let's call it T, and I want to sell it as an abstract type in Haskell. I want to use C functions as if they were of type T -> T (pure function, returns a modified copy of the input) and the question is, how to do the memory allocation for that, in particular, how to avoid IO showing up in the (visible) types on the Haskell side: I don't want IO because I don't want to declare some artificial order of execution - instead I want lazy evaluation. E.g., I might have some Haskell record with a T component which may or may not be evaluated (accessed) at all. I came up with two straightforward approaches that don't work: Version 1: the C function does "malloc" on its own, and returns a Ptr. So far, this is pure (no IO). Problem: to make the "free" happen, I need to add a finalizer in Haskell, and this is IO. Version 2: allocation on the Haskell side with mallocForeignPtr. Problem: this is already in IO. Is there a solution? Workaround? Better approach? If it boils down to unsafePerformIO, then where do I put it, and what should I watch out for? J.W.

Excerpts from Johannes Waldmann's message of Thu Oct 14 13:45:46 -0400 2010:
Is there a solution? Workaround? Better approach? If it boils down to unsafePerformIO, then where do I put it, and what should I watch out for?
unsafePerformIO is your ticket here. The key is to ensure all of the usual purity contracts are fulfilled by the composition of IO operations you are shoving into the pure world. I did a presentation on this for one particular FFI library: check the second half of the slide deck. http://web.mit.edu/~ezyang/Public/galois.pdf Cheers, Edward

On Thu, 2010-10-14 at 17:45 +0000, Johannes Waldmann wrote:
Hi. I wonder how to do the following properly.
I have one (large) C type, let's call it T, and I want to sell it as an abstract type in Haskell.
I want to use C functions as if they were of type T -> T (pure function, returns a modified copy of the input) and the question is, how to do the memory allocation for that, in particular, how to avoid IO showing up in the (visible) types on the Haskell side:
I don't want IO because I don't want to declare some artificial order of execution - instead I want lazy evaluation. E.g., I might have some Haskell record with a T component which may or may not be evaluated (accessed) at all.
It is exactly for this purpose that the Haskell FFI library includes unsafePerformIO. This is basically *the* legitimate use case for it, so you don't need to feel bad about it. The FFI spec says: Sometimes an external entity is a pure function, except that it passes arguments and/or results via pointers. To permit the packaging of such entities as pure functions, Foreign provides the following primitive: unsafePerformIO :: IO a -> a http://www.cse.unsw.edu.au/~chak/haskell/ffi/ffi/ffise5.html#x8-240005.1 Duncan

Duncan Coutts
It is exactly for this purpose that the Haskell FFI library includes unsafePerformIO. This is basically *the* legitimate use case for it, so you don't need to feel bad about it.
OK, thanks. Then this means my C type is a ForeignPtr, and each time I use it (even read-only) it looks like unsafePerformIO $ withForeignPtr $ \ p -> ... Meanwhile I think I found a nice example and explanation here: http://en.wikibooks.org/wiki/Haskell/FFI#Self-Deallocating_Pointers J.W.

On Fri, 15 Oct 2010 09:07:22 +0100, Duncan Coutts
On Thu, 2010-10-14 at 17:45 +0000, Johannes Waldmann wrote:
Hi. I wonder how to do the following properly.
I have one (large) C type, let's call it T, and I want to sell it as an abstract type in Haskell.
I want to use C functions as if they were of type T -> T (pure function, returns a modified copy of the input) and the question is, how to do the memory allocation for that, in particular, how to avoid IO showing up in the (visible) types on the Haskell side:
I don't want IO because I don't want to declare some artificial order of execution - instead I want lazy evaluation. E.g., I might have some Haskell record with a T component which may or may not be evaluated (accessed) at all.
It is exactly for this purpose that the Haskell FFI library includes unsafePerformIO. This is basically *the* legitimate use case for it, so you don't need to feel bad about it.
I still feel bad about it. Its so easy to turn unsafePerformIO into unsafeCoerce, that I can well happen by mistake. I would like to have an unsafePerformIO that is only unsafe w.r.t. performing effects, not breaking the type-system. Here is a suggestion, it may be not new but I never seen it on unsafePerformIO: unsafePerformIO :: Typeable a => IO a -> a unsafePerformIO = ... same code ... Provided that Typeable instance are all generated by the compiler this has the desired effect of preventing generalization of mutable data. Best regards, -- Nicolas Pouillard http://nicolaspouillard.fr
participants (4)
-
Duncan Coutts
-
Edward Z. Yang
-
Johannes Waldmann
-
Nicolas Pouillard