Whoops, now I see a real problem with what I'm asking for.
I guess since the (hypothetical) withCString is creating a new CString (bit like an IORef) it should have type
withCString :: String -> (CString -> b) -> IO b
It's still highly dangerous. When will the string be freed (no you can't rely on the garbage collector, because a CString is a Ptr and not a ForeignPtr; so the string has to be freed explicitly). Assuming your type for withCString... foreign import ccall foo :: CString -> Word32 -> Word32 main = do bar <- (withCString "Hello, world." foo) :: IO (Word32 -> Word32) print (bar 42) OK, what does this do: The first statement in "main": *) Allocates a buffer for the string and pokes the string in there. *) Binds the first parameter to foo (i.e., allocates a partial application (PAP) on the haskell heap). *) Frees the string buffer. The print statement: *) calls the foreign function "foo" with the pointer to the already-freed (!) string buffer and the number 42 as arguments *) prints the result
and I guess my <+ should be.. (<+) :: (a -> b) -> ((a -> IO b) -> IO b) -> IO b f <+ alloc = alloc $ \p -> return $ f p
(Well at least that's got rid of the unsafePerformIO :-)
Would this be safe?
It would probably be safer than the version with the unsafePerformIO, but still: foreign import ccall foo :: CString -> Word32 -> Word32 main = do bar <- foo <+ withCString "Hello, world." print (bar 42) ... same problem as above. Cheers, Wolfgang