I am a newcomer to Haskell and I'm offering my perspective on the troubles I endured trying to make Haskell interface to some simple C programs. It is my hope, that by documenting this, someone else will benefit from my mistakes and errors and climb the learning curve somewhat faster than me. I was attracted to Haskell, after playing around with OCAML, and realizing that functional programming offers some nice advantages to scientific programming. Mainly because the notation and thinking is very mathematical. But first, in order to evaluate the suitability of this language for my purposes, I had to verify that the foreign function interface (FFI) was suitable. There are a number of numerical libraries, all in imperative languages, that I want to link to. I quickly discovered that the documentation on Haskell's FFI is rather poor currently. This topic is simply not of interest to the academics I suppose. It took many hours of searching to find this document: http://www.cs.caltech.edu/courses/cs11/material/haskell/papers/tackling_the_... This little tutorial was a goldmine of information about monads and an introduction to the FFI. (No template solutions for my problem sorry to say.) It was certainly dismaying to see that even the simplest IO requires at least a minimal understanding of monads, and adds a bunch of extra semantics to the problem. However none of the solutions offered, even the automated ones, seemed to handle the case of passing numerical arrays to C, and having them get updated and passed back. That is my primary interest in the FFI and yet no obvious solution or example could be found after days of internet searching and pouring over tutorials etc. My conclusion, after hours of studying the hierarchical libraries was that I needed to use the StorableArray type which led me to this site, http://www.haskell.org/haskellwiki/Arrays#StorableArray_.28module_Data.Array... This site proposes the following curious piece of code: {-# OPTIONS_GHC -fglasgow-exts #-} import Data.Array.Storable import Foreign.Ptr import Foreign.C.Types main = do arr <- newArray (1,10) 37 :: IO (StorableArray Int Int) readArray arr 1 >>= print withStorableArray arr $ \ptr -> memset ptr 0 40 readArray arr 1 >>= print foreign import ccall unsafe "string.h" memset :: Ptr a -> CInt -> CSize -> IO () After having freshly read the tutorial on monads I thought I was ready for this, but I ran into some parsing problems. I don't have a full grasp of the precedence rules for the operators, >>= , $ and function evaluation are, and whether they group left to right or right to left. A little type parsing on the inputs and outputs allowed me to resolve all but the line withStorableArray arr $ \ptr -> memset ptr 0 40 Which should resolve to a monad if I understand the do notation correctly. My first assumption was that $ has lower precedence than function application, but a higher precendence than >> or >>=, so I assumed the grouping, (withStorableArray arr) $ (\ptr -> (memset ptr 0 40)) Now withStorableArray has the type specification StorableArray i e -> (Ptr e -> IO a) -> IO a , so it should be obvious how to use it (Not). At any rate it takes two arguments so I might assume that (withStorableArray arr) curries the first argument so that this expression is a function of type (Ptr e -> IO a) -> IO a . Because of the type of the array, it appears that a = Int. However (\ptr -> (memset ptr 0 40)) should be a function of type Ptr a -> IO(a) in order to qualify as the second argument of withStorableArray. This almost fits, but not quite. memset should return type IO(Int) for this to work correctly, however according to it's type declaration it returns IO (). Shouldn't the compiler complain about this? So after about 10 hours of wrestling with syntax, including messing up the initial capitalization of module names, indenting in do lists, forgetting to put commas in tuples and lists I finally got the following example to compile without error or warning Matrix.hs __________ import Foreign import Foreign.C import Foreign.C.Types (CInt, CDouble ) import Data.Array.Storable foreign import ccall "matrix_c.h sumarr" sumarr :: Ptr CDouble -> CDouble main = do arr <- newListArray (1 , 3) [3,2,1]:: IO (StorableArray Int CDouble) -- extract the pointer to arr dsum <- withStorableArray arr (\ptr -> return (sumarr ptr )) print dsum matrix_c.c ------------------ #include <math.h> double sumarr(double *in) { return(in[0] + in[1]) ; } This is how I compiled it using ghc 6.4.2
ghc -c matrix_c.o matrix_c.c ghc -O -o Matrix.exe -fglasgow-exts Matrix.hs matrix_c.o
It runs correctly
Matrix 5.0
Notes: ---------------------------------------------- Matrix.exe fails to work correctly if the header file matrix_c.h is not included in the foreign import statement The hack? where the second argument of withStorableArray is a -> IO() instead of a -> IO(a) allows the do clause to be simplified to main = do arr <- newListArray (1 , 3) [3,2,1]:: IO (StorableArray Int CDouble) withStorableArray arr $ print . sumarr If one changes the array in[] in the C code, e.g. double sumarr(double *in) { in[0] = -10.0 ; return(in[0] + in[1]) ; } The array is changed inside the haskell program as a side effect. main = do arr <- newListArray (1 , 3) [3,2,1]:: IO (StorableArray Int CDouble) -- extract the pointer to arr withStorableArray arr $ print . sumarr (readArray arr 1 ) >>= print I suppose this is one way to 'pass' arrays back to Haskell.