hsc2hs: Mutate a C struct с Haskell

Я пытаюсь написать программу Haskell, которая связывается с C (в конечном счете, для iOS через GHC-iOS). Я хочу, чтобы он передавал строку из C в Haskell, обрабатывал ее Haskell, а затем возвращал некоторые типы данных из Haskell в C Structs через hsc2s. Мне не удалось найти ясный, простой учебник. Единственное, что нужно от Haskell от C, – это String, и ничего больше.

У меня нет проблем с самой первой частью, передавая строку Хаскелу.

testPrint :: CString -> IO () testPrint c = do s <- peekCString c putStrLn s 

Для целей тестирования и будущей ссылки я просто хочу иметь возможность обрабатывать что-то вроде следующего.

C Struct

 struct testdata { char *a; char *b; int c; }; 

Тип данных Haskell

 data TestData = TestData { a :: String, b :: String, c :: Int } deriving Show -- not sure what the type would look like testParse :: CString -> TestData 

Я понимаю, что мне нужно, чтобы typeclass TestData как Storable и реализовал peek, poke, sizeOf и выравнивание, но мне нужно увидеть простой пример, прежде чем я действительно смогу его понять. Большинство учебных пособий требуют внешних библиотек и делают их более сложными, чем нужно.

Вот ресурсы, на которые я смотрел:

Stackoverflow – Как использовать hsc2hs для привязки к константам, функциям и структурам данных?

Haskell Cafe – FFI для начинающих

Написание интерфейсов Haskell для кода C: hsc2hs

Haskell Wikibook – FFI

Изменить: В настоящее время, где я застреваю (получает ошибку сегментации, когда setFoo вызывается в C)

Фрагмент кода Haskell

 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 Код fragmentа

 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); 

Это полный пример программы C, передающей структуру Haskell, тогда Haskell мутирует значения этой структуры. Он не имеет внешних зависимостей. Вы должны иметь возможность скопировать код и запустить его, если у вас есть GHC. Надеюсь, это послужит простым, простым примером для других.

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  #include  #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:\na: %s\nb: %s\nc: %d\n",f->a,f->b,f->c); setFoo(f); printf("foo has been set in Haskell:\na: %s\nb: %s\nc: %d\n",f->a,f->b,f->c); free_HaskellPtr(f->a); free_HaskellPtr(f->b); free(f); hs_exit(); } 

Командная строка. Скомпилируйте файлы и выполните

 $ hsc2hs HsFoo.hsc $ ghc -c HsFoo.hs foo.c $ ghc -no-hs-main foo.c HsFoo.o main.c -o main $ ./main