我正在查看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操作但丢弃其结果
答案 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代码是了解正在发生的事情的一种非常好的方法