[Haskell-cafe] example of FFI FunPtr

Ryan Ingram ryani.spam at gmail.com
Sat Jun 7 16:20:03 EDT 2008

2008/6/6 Galchin, Vasili <vigalchin at gmail.com>:
>      I want to do an incremental "experiment". I want just want  to pass a C
> function to "callback" to a Haskell function. ???

This is easy; just declare the function via the FFI; here's an example
from my implementation for the 2006 ICFP contest
(http://www.boundvariable.org/); this interface is used to get access
to a fast C VM from the high-level haskell debugger.  The C VM can
call back into Haskell in order to get and fetch characters from the
console, and to notify the debugger of allocations and frees. The
haskell-side debugger can query the state of the VM via the "get"
functions exported by the VM.

In this example, get_program_size is a first class haskell IO action;
it can be passed around like any other action.  If you know the
function call is referentially transparent (pure), you can leave the
"IO" off of the return result of the function; be careful with this,
it's calling into whatever C-code you are giving and so you should
treat it as carefully as you treat unsafePerformIO.

The "unsafe" keyword allows GHC to optimize certain calls; in order to
use it you need to know that the function won't call back into Haskell

foreign import ccall unsafe load_program :: Ptr Word32 -> Word32 -> IO ()
foreign import ccall execute :: Word32 {-numCycles-}
                                -> FunPtr GetChar
                                -> FunPtr PutChar
                                -> FunPtr Notify {-alloc-}
                                -> FunPtr Notify {-free-}
                                -> IO Word32 {-returnCode 0=success, 1=failure-}
foreign import ccall unsafe get_program :: IO (Ptr Word32)
foreign import ccall unsafe get_program_size :: IO Word32
foreign import ccall unsafe get_registers :: Ptr Word32
foreign import ccall unsafe get_pc :: IO Word32
foreign import ccall unsafe get_prev_pc :: IO Word32
foreign import ccall unsafe set_pc :: Word32 -> IO Bool

type GetChar = IO Word32
type PutChar = Word32 -> IO ()
type Notify = Ptr Word32 -> Word32 -> IO ()
foreign import ccall "wrapper" mkGetChar :: GetChar -> IO (FunPtr GetChar)
foreign import ccall "wrapper" mkPutChar :: PutChar -> IO (FunPtr PutChar)
foreign import ccall "wrapper" mkNotify :: Notify -> IO (FunPtr Notify)

More information about the Haskell-Cafe mailing list