在Python中,我可以这样做:
import ctypes
import ctypes.util
my_lib = ctypes.cdll.LoadLibrary (ctypes.util.find_library ('my_lib') or 'my_lib32')
a = my_lib.some_function(33)
b = my_lib.some_function2(33)
c = my_lib.SOME_CONST_123
由于我需要将这种类型的Python代码转换为Haskell,我想知道我可以在Haskell中做同样的事情吗?我知道我可以通过FFI这样的事情。 但它并不完全是我在Python中可以做到的,因为就我在Haskell中所关注的而言,我必须首先声明这些函数,如下所示:
foreign import ccall "my_lib.h some_function"
some_function :: CDouble -> CDouble
这是真的,有更简单的方法吗?
答案 0 :(得分:4)
Python中的ctypes库基本上是C库libffi
的包装器,它是一个库,让我们在进程的地址空间中调用任意函数,在运行时而不是编译时给出信息。
可以在Haskell中使用same library和动态链接器来实现相同的效果:
import Foreign.LibFFI
import System.Posix.DynamicLinker
example :: IO ()
example = do
dlopen "mylib.so" [RTLD_LAZY]
fn <- dlsym Default "some_function"
fn2 <- dlsym Default "some_function2"
a <- callFFI fn retCInt [argCInt 33]
b <- callFFI fn2 retCInt [argCInt 33]
return ()
由于很多原因,这并不理想,我不建议构建一大堆这样的绑定,原因与许多Python开发人员不赞成使用ctypes进行绑定一样,除非作为最后的手段。对于一个,它将为每个函数调用提供一些开销(与ctypes具有大致相同的开销)。与来自Haskell的ccall unsafe
FFI函数相比has basically no overhead并且与本机C函数调用一样便宜。
其次,不是使用简单的Haskell类型的参数,如Int
和Float
函数的参数现在都在一个巨型的libffi和类型Arg
中,它对类型系统是不透明的很容易引入微妙的错误。
如果你可以在编译时链接C库并向前声明函数,要么使用常规的Haskell FFI(-XForeignFunctionInterface
)和/或像c2hs这样的工具,它将使生活变得更加容易。