我使用FFI来调用一个C函数,它接受一个结构体并返回同样的结构体。我看到的参考资料都说我必须使用这些结构体的指针才能将其导入Haskell。例如:
现在我有一个问题,需要使用该函数。我看到的参考链接中,这些函数类型为 BarPtr -> IO ()并使用了 with ,其签名为 Storable a => a -> (Ptr a -> IO b) -> IO b,这是可以的,因为它们在main函数内部调用该函数。
然而,我想将这个函数包装成一个库,获得一个没有IO的 Bar -> Bar 类型的函数,是否可以在不使用 unsafePerformIO 的情况下实现呢?程序流程是什么?
data Bar = Bar { a :: Int, b :: Int }
type BarPtr = Ptr (Bar)
foreign import ccall "static foo.h foo"
f_foo :: BarPtr -> BarPtr
现在我有一个问题,需要使用该函数。我看到的参考链接中,这些函数类型为 BarPtr -> IO ()并使用了 with ,其签名为 Storable a => a -> (Ptr a -> IO b) -> IO b,这是可以的,因为它们在main函数内部调用该函数。
然而,我想将这个函数包装成一个库,获得一个没有IO的 Bar -> Bar 类型的函数,是否可以在不使用 unsafePerformIO 的情况下实现呢?程序流程是什么?
Ptr A -> IO ()
的东西得到一个纯函数,那么相应的 C 函数必须是“几乎纯”的,也就是说它唯一的效果就是修改其参数指向的内存。如果满足这个条件,你可以使用 Storable 和alloca
来创建一个指向 C 的指针,然后从该指针读取并返回值来编写类型为A -> A
的函数。这个函数在道德上是纯洁的,因为它没有可观察的影响,所以在它上面调用unsafePerformIO
是完全可以的(实际上这就是unsafePerformIO
的预期使用方式)。 - user2407038