I am trying to write a Haskell program that communicates with C (ultimately for iOS via GHC-iOS). I want it to pass a string from C to Haskell, have Haskell process it and then return some Data types from Haskell to C Structs via hsc2s. I have been unsuccessful at finding a clear, simple tutorial. The only thing Haskell needs from C is the String, nothing else.
I have no trouble with the very first part, passing a string to Haskell.
testPrint :: CString -> IO ()
testPrint c = do
s <- peekCString c
putStrLn s
For test purposes and future reference, I just want to be able to handle something like the following.
C Struct
struct testdata {
char *a;
char *b;
int c;
};
Haskell Data Type
data TestData = TestData {
a :: String,
b :: String,
c :: Int
} deriving Show
-- not sure what the type would look like
testParse :: CString -> TestData
I understand that I need to typeclass TestData as Storable and implement peek, poke, sizeOf and alignment, but I need to see a simple example before I can really understand it. Most of the tutorials require outside libraries and make it more complicated than it needs to be.
Here are the resources I've looked at:
Stackoverflow - How to use hsc2hs to bind to constants, functions and data structures?
Haskell Cafe - FFI for a beginner
Writing Haskell interfaces to C code: hsc2hs
Haskell Wikibook - FFI
Edit: Currently where I am stuck (gets segmentation error when setFoo is called in C)
Haskell Code Snippet
instance Storable Foo where
sizeOf = #{size foo}
alignment = alignment (undefined :: CString)
poke p foo = do
#{poke foo, a} p $ a foo
#{poke foo, b} p $ b foo
#{poke foo, c} p $ c foo
peek p = return Foo
`ap` (#{peek foo, a} p)
`ap` (#{peek foo, b} p)
`ap` (#{peek foo, c} p)
foreign export ccall "setFoo" setFoo :: Ptr Foo -> IO ()
setFoo :: Ptr Foo -> IO ()
setFoo f = do
newA <- newCString "abc"
newB <- newCString "def"
poke f (Foo newA newB 123)
C Code Snippet
foo *f;
f = malloc(sizeof(foo));
foo->a = "bbb"
foo->b = "aaa"
foo->c = 1
// this is incorrect
// setFoo(&f);
// this is correct
setFoo(f);