calling haskell from C from haskell

Alastair Reid
Fri, 03 Jan 2003 16:40:55 +0000

> Hello, Is calling haskell from C from haskell possible? This is what
> i tried (generated with green-card):

It ought to work.  Instead of using Greencard (which only supports
Haskell->C) or the old _casm_ operation, I'd recommend using the new
foreign function interface.

In particular you should look at 'foreign import' (for Haskell->C
calls) and 'foreign export' or 'foreign import wrapper' (for C ->
Haskell calls).  I'm attaching part of the Hugs test suite which shows
how to use 'foreign import' and 'foreign import wrapper' to call from
Haskell -> C -> Haskell.

Benefits of using the ffi are that your code will be portable to other
compilers (Hugs and NHC) and you'll be in well charted waters where
you can be confident that if things don't work then you've found a bug
and not an undocumented feature.

Alastair Reid         
Reid Consulting (UK) Limited

Here's part of the Hugs test suite (hugs98/tests/ffi/Sin.hs).  The
most relevant example is the third test which creates and uses

-- !!! Testing static, dynamic and wrapped import of trig function

-- Imports kept minimal to avoid pulling in Storable and other
-- things which use even more ffi.
import IOExts( unsafePerformIO )
import Ptr( FunPtr, freeHaskellFunPtr )

tests = do

  putStrLn "\nTesting sin==mysin (should return lots of Trues)"
  print (testSin sin mysin)

  putStrLn "\nTesting sin==dynamic_sin (should return lots of Trues)"
  print (testSin sin (dyn_sin sin_addr))

  putStrLn "\nTesting sin==IO wrapped_sin (should return lots of Trues)"
  sin_addr2 <- wrapIO (return . sin)
  print (testSin sin (unsafePerformIO . (dyn_sinIO sin_addr2)))
  freeHaskellFunPtr sin_addr2

  putStrLn "\nTesting sin==Id wrapped_sin (should return lots of Trues)"
  sin_addr3 <- wrapId sin
  print (testSin sin (dyn_sin sin_addr3))
  freeHaskellFunPtr sin_addr3

testSin f g = [ (f x == g x) | x <- [0,0.01 .. 1] ]

foreign import ccall "math.h sin" mysin :: Double -> Double
foreign import ccall "dynamic" dyn_sin :: FunPtr (Double -> Double) -> (Double -> Double)
foreign import ccall "dynamic" dyn_sinIO :: FunPtr (Double -> IO Double) -> (Double -> IO Double)
foreign import ccall "math.h &sin" sin_addr :: FunPtr (Double -> Double)
foreign import ccall "wrapper" wrapId :: (Double -> Double) -> IO (FunPtr (Double -> Double))
foreign import ccall "wrapper" wrapIO :: (Double -> IO Double) -> IO (FunPtr (Double -> IO Double))