haskell – c2hs in-and-type-marshalling

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

int MPI_Initialized (int *flag); 

在Internal.chs中表示如下:

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

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

>什么是 – 修饰符呢? c2hs wiki说“Hs函数的参数类型是由所有编组规范的集合决定的,其中in marshaller后面没有减号”,但我仍然没有得到它.
> C函数接受一个指向int的指针;输出编组器在做什么? AFAICT,它取消引用指针并将结果转换为布尔值.它是否正确?

注意:MPI_前缀在函数名称中由{#interign prefix =“MPI”#}引入.

NB2:

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

NB3:discard _ = return(),* – 修饰符用于运行monadic动作但丢弃其结果

最佳答案 我发现理解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

这里,函数钩子中输入参数的marshaller后面的“ – ”意味着该参数实际上并不作为生成的Haskell函数的参数出现 – 在这种情况下,会发生的事情是为参数分配了一些空间对于MPI_Initialized(使用alloca),使用指向该分配空间的指针调用C函数,并使用peekBool返回Haskell函数的输出以从分配的空间中提取值.

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

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

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

点赞