如何从外部代码中确定数据的构造函数?

arr*_*owd 5 haskell ffi

在我的Haskell程序中,我有一个带有许多构造函数的ADT:

data MyData = Con1 |
    Con2 |
    ...
    Con20
Run Code Online (Sandbox Code Playgroud)

我有一个foreign export ccall函数,它包含[MyData]在数组中StablePtr's.在调用它之后,我需要确定使用了哪个构造函数来构造每个元素.

它可以通过这种方式解决

foreign export ccall getType :: StablePtr MyData -> IO CInt
getType (Con1) = return 1
getType (Con2) = return 2
...
Run Code Online (Sandbox Code Playgroud)

但后来我需要在C头中手动定义这些常量.这很容易出错,所以我想知道是否有办法让GHC为我做这个工作.

Don*_*art 5

派生Enum你的Haskell类型,并导出fromEnumMyData :: MyData -> Int ; fromEnumMyData = fromEnum.

然后,您可以通过查看Int标签GHC分配来在C端进行案例分析.

  • 我希望GHC将`#define CON1_ID 1`,`#define CON2_ID 2`,...等内容放入生成的头文件中. (3认同)

arr*_*owd 0

我已经找到了解决方案。

我在 C 代码中将可能的构造函数类型定义为枚举:

typedef enum
{
    MyDataCon1,
    MyDataCon2,
    ...
    MyDataCon20
} MyDataConstructor;
Run Code Online (Sandbox Code Playgroud)

然后我在我的 Haskell 源代码中使用了C->Haskell枚举钩子:

{#enum MyDataConstructor deriving (Show) #}
Run Code Online (Sandbox Code Playgroud)

预处理后,该行变为

data MyDataConstructor = MyDataCon1
    | MyDataCon2
    ...
    | MyDataCon20
Run Code Online (Sandbox Code Playgroud)

现在我可以getType这样定义:

foreign export ccall getType :: StablePtr MyData -> IO CInt
getType md = do
    md' <- deRefStablePtr md
    case md' of
        Con1 -> return $ fromEnum MyDataCon1
        Con2 -> return $ fromEnum MyDataCon2
        ...
        Con20 -> return $ fromEnum MyDataCon20
Run Code Online (Sandbox Code Playgroud)