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);
This is a complete example of a C program that passes a struct to Haskell then Haskell mutates the values of that struct. It has no outside dependencies. You should be able to copy the code and run it if you have GHC. Hopefully this will serve as a simple, straightforward example for others.
Foo.h
typedef struct {
char *a;
char *b;
int c;
} foo;
Foo.c
#include "foo.h"
HsFoo.hsc
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE CPP #-}
module HsFoo where
import Foreign
import Foreign.C
import Control.Applicative
import Control.Monad
#include "foo.h"
data Foo = Foo {
a :: CString
, b :: CString
, c :: Int
} deriving Show
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 "free_HaskellPtr" free :: Ptr a -> IO ()
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 3
return ()
main.c
#include <stdio.h>
#include <stdlib.h>
#include "HsFoo_stub.h"
#include "foo.h"
int main(int argc, char *argv[]) {
hs_init(&argc, &argv);
foo *f;
f = malloc(sizeof(foo));
f->a = "Hello";
f->b = "World";
f->c = 55555;
printf("foo has been set in C:\n a: %s\n b: %s\n c: %d\n",f->a,f->b,f->c);
setFoo(f);
printf("foo has been set in Haskell:\n a: %s\n b: %s\n c: %d\n",f->a,f->b,f->c);
free_HaskellPtr(f->a);
free_HaskellPtr(f->b);
free(f);
hs_exit();
}
Command Line - Compile files and run
$ hsc2hs HsFoo.hsc
$ ghc -c HsFoo.hs foo.c
$ ghc -no-hs-main foo.c HsFoo.o main.c -o main
$ ./main
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With