4

我正在查看haskell-mpi 绑定,例如,我们有这个签名mpi.h

int MPI_Initialized (int *flag); 

其中 inInternal.chs表示如下:

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

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

  • -修改器在做什么?c2hs wiki 说“Hs 函数的参数类型由所有编组规范的集合决定,其中 in 编组器后面没有减号”,但我仍然不明白。

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

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

NB2:

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

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

4

1 回答 1

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 函数,并返回 Haskell 函数的输出,使用peekBool从分配的空间中提取值。

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

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

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

于 2015-04-19T19:29:31.493 回答