c2hs 输入和输出类型编组

c2hs in- and out- type marshalling

我正在查看 haskell-mpi binding,我们有例如mpi.h 中的签名:

int MPI_Initialized (int *flag); 

其中在Internal.chs中表示如下:

{#fun unsafe Initialized as ^ {alloca- `Bool' peekBool*} -> `()' discard*- #}

问:我无法理解输入参数周围发生的事情:

注意:MPI_ 前缀由 {# context prefix="MPI"#}.

在函数名称中引入

NB2:

peekBool :: (Storable a, Num a, Eq a) => Ptr a -> IO Bool
peekBool = liftM toBool . peek

NB3:discard _ = return (),并且 *- 修饰符用于 运行 单子操作但丢弃其结果

我发现了解 C2HS 功能的最简单方法是查看它生成的 Haskell 代码。在这种情况下,函数 hook

{#fun unsafe Initialized as ^ {alloca- `Bool' peekBool*} -> `()' discard*- #}

产生以下 Haskell 代码(稍微整理一下):

initialized :: IO Bool
initialized =
  alloca $ \a -> 
  initialized'_ a >>= \res ->
  discard res >> 
  peekBool a

foreign import ccall unsafe "Control/Parallel/MPI/Internal.chs.h MPI_Initialized"
  initialized'_ :: Ptr CInt -> IO CInt

这里,函数挂钩中输入参数的编组器后面的“-”意味着该参数实际上并未作为结果 Haskell 函数的参数出现——在在这种情况下,会发生一些 space 被分配给 MPI_Initialized 的参数(使用 alloca),使用指向分配的 space 的指针调用 C 函数,并且Haskell 函数的输出是 returned 使用 peekBool 从分配的 space.

中提取值

C2HS产生的Haskell函数的类型只是IO Bool,即"input"参数没有出现在任何地方。 (C2HS 文档确实有点这样说,但在您看到示例之前很难解释它的含义!)

输出编组器只是丢弃调用 MPI_Initialized C 函数的结果,这是一个在这种情况下不是很有趣的状态代码。 C2HS 生成的 Haskell 代码的 real return 结果是由 MPI_Initialized 函数的指针参数的输出编组器生成的。 peekBool 函数从 C int * 指针中读取一个整数值并将其转换为 Haskell Bool;输出编组器中的“*”意味着这个值应该在 IO monad 中被 returned。

这种分配模式以“-”作为输入编组器,某种 "peek" 函数以 "IO *" 作为输出编组器(并且经常丢弃 C 函数的 return 值也是如此)很常见。许多 C 库使用这种通过指针分配结果的模式,并且在 Haskell 中手动跟踪指针分配很烦人,因此 C2HS 试图帮助您管理它。需要一段时间才能习惯将所有“-"s and "*”放在哪里,但是查看 C2HS 生成的 Haskell 代码是一个非常好的方法了解发生了什么。