我使用以下习语继承了代码库,该代码库通过FFI导出然后重新导入函数:
foreign export ccall someHaskellFn :: a -> IO b
foreign import ccall "&someHaskellFn"
someHaskellFn_addr :: FunPtr (a -> IO b)
Haskell函数someHaskellFn
和导出的函数都没用过;只需要someHaskellFn_addr
,并且始终在IO上下文中使用:
-- frob :: FunPtr (a -> IO b) -> IO ()
frob someHaskellFn_addr
我想知道这是否比使用包装器功能有任何优势:
foreign import ccall "wrapper"
mkWrapper :: (a -> IO b) -> IO (FunPtr (a -> IO b))
-- Function pointer to someHaskellFn, never freed
someHaskellFnPtr = mkWrapper someHaskellFn
frob =<< someHaskellFnPtr
Foreign.Ptr的文档提到了这两种方法来创建FunPtr a
类型的值:
FunPtr类型的值可以是指向外部函数的指针, 要么由另一个外国函数返回,要么用a导入 静态地址导入,如
foreign import ccall "stdlib.h &free" p_free :: FunPtr (Ptr a -> IO ())
或指向使用包装器存根创建的Haskell函数的指针 声明生成一个正确类型的FunPtr。
它也说
调用包装器存根[...]分配存储,当不再需要时,应该使用freeHaskellFunPtr释放存储。
我的理解是使用代码的包装器表现为导出/导入变体的(在Haskell端)。它是否正确?有没有关于我缺少的外国功能进口和出口的更详细信息?