c2hs in-and-type-marshalling

时间:2015-04-15 15:46:11

标签: haskell ffi c2hs

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

int MPI_Initialized (int *flag); 

Internal.chs表示如下:

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

问:我在理解输入参数周围发生的事情时遇到了一些麻烦:

  • -修饰符在做什么? c2hs wiki说“Hs函数的参数类型是由所有编组规范的集合决定的,其中inrs marshaller后面没有减号”,但我仍然没有得到它。

  • C函数指向int;输出编组器在做什么? AFAICT,它取消引用指针并将结果转换为布尔值。这是对的吗?

注意:MPI_前缀由函数名{# context prefix="MPI"#}引入。

NB2:

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

NB3:discard _ = return ()*-修饰符用于执行monadic操作但丢弃其结果

1 个答案:

答案 0 :(得分:2)

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

{#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函数的参数出现 - 在这种情况下会发生的是为MPI_Initialized的参数分配了一些空间(使用alloca),使用指向该分配空间的指针调用C函数,并使用peekBool返回Haskell函数的输出从分配的空间中提取值。

C2HS产生的Haskell函数的类型只是IO Bool,即“输入”参数不会出现在任何地方。 (C2HS文档确实有这样的说法,但在你看到一个例子之前很难解释它的含义!)

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

这种分配模式使用“-”作为输入编组器,某种“peek”函数带有“IO *”作为输出编组器(并且经常丢弃C函数的返回值)同样)很常见。许多C库使用这种通过指针分配结果的模式,并且在Haskell中手动跟踪指针分配是令人讨厌的,因此C2HS尝试帮助为您管理。需要一段时间才能习惯放置所有“-”和“*”的位置,但查看C2HS生成的Haskell代码是了解正在发生的事情的一种非常好的方法