基于复杂的Haskell类型生成C结构

时间:2013-01-24 11:44:23

标签: c haskell ffi

我正在尝试在我的C代码中使用Haskell库。我尝试使用的Haskell函数的类型为String -> IO [Reference],其中Reference是一个相当复杂的结构(参见here for details)。

基于阅读各种文档,似乎我必须使这种类型成为Storable的实例,并且在我的c代码中定义了类似的结构才能访问它。对于如此复杂的类型,这似乎是很多非常重复的工作。有没有办法实现自动化?怎么会做这样的事情?

2 个答案:

答案 0 :(得分:8)

这取决于你的实际用例,但是...... 可以更轻松地将Reference导出为opaque类型(通过Foreign.StablePtr),并导出getter函数以访问各个字段。

如果您需要更多详细信息,请告诉我,我会扩大答案。

答案 1 :(得分:4)

我写了一个小工具(使用Template Haskell),它自动编组包含基本类型(Int,Float,Double,Char,Bool),可编组类型列表和由可编组类型组成的结构的任何数据类型进入相应的C类型。

  • 原始类型成为它们的C对应物:Int - > int,Float - >浮动。 Bool成为int。
  • “Structs”(数据S = S ...)成为具有Haskell“struct”的编组成员的结构的指针。
  • Arrays([S])成为一个结构的指针,该结构包含指向该类型指针数组的指针,以及一个int,告诉其中有多少元素。

所以这个:

data Test = Test [MyStruct] Int
data MyStruct = MyStruct Int

在C中会是这样的:

struct MyStruct {
  int x;
}

struct ArrayStruct {
  MyStruct** array;
  int count;
}

struct Test {
  ArrayStruct* arr_str;
  int y;
}

这是工具: https://github.com/food2games/fieldmarshal

(它也有一个C#部分,但你需要HsFieldMarshal。)它由两个文件组成,你只需将它们复制到你的代码中即可。用法:

$(makeStorable ''YourType)

请注意,它不会自动为子类型执行可存储代码,所以如果你有这个:

data Type1 = Type1 Int Float
data Type2 = Type2 Int Type1

比必须为每种数据类型生成可存储实例:

$(makeStorable ''Type1)
$(makeStorable ''Type2)

另请注意,您必须在可存储实例生成之前声明数据类型(这是因为TH)。所以这不起作用:

$(makeStorable ''Wrong)
data Wrong = Wrong Int

这绝对不是万无一失的,对于简单的应用程序来说已经足够了,但是如果你正在使用更复杂的代码,那么事情就会很容易搞砸。