hsc2hs:用 Haskell 改变 C 结构
hsc2hs: Mutate a C struct with Haskell
我正在尝试编写一个与 C 通信的 Haskell 程序(最终 iOS 通过 GHC-iOS)。我希望它将一个字符串从 C 传递到 Haskell,让 Haskell 处理它,然后 return 通过 hsc2s 从 Haskell 到 C Structs 的一些数据类型。我未能找到清晰、简单的教程。 Haskell C 需要的唯一东西就是字符串,没有别的。
第一部分我没有问题,将字符串传递给 Haskell。
testPrint :: CString -> IO ()
testPrint c = do
s <- peekCString c
putStrLn s
出于测试目的和未来参考,我只想能够处理如下内容。
C 结构
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
我知道我需要将 TestData 类型化为 Storable 并实现 peek、poke、sizeOf 和对齐,但我需要看一个简单的例子才能真正理解它。大多数教程都需要外部库并使其变得比需要的更复杂。
以下是我看过的资源:
Whosebug - 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
编辑:目前我被卡住了(在 C 中调用 setFoo 时出现分段错误)
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 代码片段
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 <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();
}
命令行 - 编译文件和运行
$ hsc2hs HsFoo.hsc
$ ghc -c HsFoo.hs foo.c
$ ghc -no-hs-main foo.c HsFoo.o main.c -o main
$ ./main
我正在尝试编写一个与 C 通信的 Haskell 程序(最终 iOS 通过 GHC-iOS)。我希望它将一个字符串从 C 传递到 Haskell,让 Haskell 处理它,然后 return 通过 hsc2s 从 Haskell 到 C Structs 的一些数据类型。我未能找到清晰、简单的教程。 Haskell C 需要的唯一东西就是字符串,没有别的。
第一部分我没有问题,将字符串传递给 Haskell。
testPrint :: CString -> IO ()
testPrint c = do
s <- peekCString c
putStrLn s
出于测试目的和未来参考,我只想能够处理如下内容。
C 结构
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
我知道我需要将 TestData 类型化为 Storable 并实现 peek、poke、sizeOf 和对齐,但我需要看一个简单的例子才能真正理解它。大多数教程都需要外部库并使其变得比需要的更复杂。
以下是我看过的资源:
Whosebug - 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
编辑:目前我被卡住了(在 C 中调用 setFoo 时出现分段错误)
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 代码片段
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 <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();
}
命令行 - 编译文件和运行
$ hsc2hs HsFoo.hsc
$ ghc -c HsFoo.hs foo.c
$ ghc -no-hs-main foo.c HsFoo.o main.c -o main
$ ./main