/* c_boolean.h */
typedef int (*Operation)(int, int);
int eval(Operation o, int a, int b);
int plus(int a, int b);
int toString(int a, char *buffer, int bufferLen);
void print(char *buffer, int bufferLen);
Pretty simple, define the binary operation as
Operation, create a function to evaluate an operation (although really, that's unnecessary but the point of the exercise is to try different things so I had to included function pointers). Then define a simple operation plus, then to add some string manipulation and Haskell managed memory a toString function that converts the int to a string. And finally, a function that returns nothing but actually does something, print.The C code is pretty dull:
/* c_boolean.c */
#include <stdio.h>
#include "c_boolean.h"
int eval(Operation o, int a, int b) {
 return o(a, b);
}
int plus(int a, int b) {
 return a+b;
}
int toString(int a, char *buffer, int bufferLen) {
 return snprintf(buffer, bufferLen, "%d", a);
}
void print(char *buffer, int bufferLen) {
 printf("%s", buffer);
 flush(stdout);
}
Like I said, boring. But the interesting stuff is coming up, the Haskell interface to the C code. To write the code, I referred to several places:
http://www.haskell.org/haskellwiki/FFI_Introduction
http://blog.danieroux.com/2007/01/01/simple-demonstration-of-haskell-ffi/
and of course the standard Foreign API functions in:
http://haskell.org/ghc/docs/latest/html/libraries/index.html
-- boolean.hs
import Foreign
import Foreign.C.Types
import Foreign.C.String
import Foreign.Ptr
type Operation = CInt -> CInt -> IO CInt
type C_Operation = FunPtr Operation
foreign import ccall "wrapper"
 mkOperation :: Operation -> IO (FunPtr Operation)
foreign import ccall "c_boolean.h eval"
 c_eval :: C_Operation -> CInt -> CInt -> IO CInt
my_eval :: Operation -> CInt -> CInt -> IO CInt
my_eval o a b = do
 co <- mkOperation o   c_eval co a b  
foreign import ccall "c_boolean.h plus"  
 c_plus :: CInt -> CInt -> IO CInt
foreign import ccall "c_boolean.h toString"
 c_toString :: CInt -> (Ptr CChar) -> CInt -> IO CInt
with_toString :: Int -> (CStringLen -> IO a) -> CInt -> IO a
with_toString l f n = allocaArray l runF
   where
     runF str = do
       len <- c_toString (fromIntegral n) str n 
       f (str, l)
foreign import ccall "c_boolean.h print" 
 c_print :: (Ptr CChar) -> CInt -> IO ()
my_print :: CStringLen -> IO ()
my_print (s, n) = c_print s (fromIntegral n)
minus :: CInt -> CInt -> IO CInt
minus a b = return (a-b)
main = do
  cp <- my_eval c_plus 2 6
  m <- my_eval minus 5 2 
  sequence_ [ putStr "C plus: ",
              with_toString 10 my_print cp, 
              putStr "\nHaskell minus: ", 
              with_toString 10 my_print m, 
              putStr "\n" ] 
Then the compilation and running:
$ gcc -I. c_boolean.c -c && ar rc c_boolean.a c_boolean.o && ranlib c_boolean.a && ghc -L. -lc_boolean -fglasgow-exts -ffi --make boolean.hs -o boolean
[1 of 1] Compiling Main             ( boolean.hs, boolean.o )
Linking boolean ...
$ ./boolean                               
C plus:                                                                         
Haskell minus: 
83$
One problem, even though I used sequence_ and flushed the printf in C, the 8 and 3 are printed at the very end.
Update, fixed formatting.