在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
这是真的,有更简单的方法吗?
解决方法:
Python中的ctypes库基本上是C库libffi的包装器,它是一个库,让我们在进程的地址空间中调用任意函数,在运行时给定信息而不是编译时.
same library可以在Haskell中与动态链接器一起使用,以实现相同的效果:
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不安全FFI函数相比,has basically no overhead并且与本机C函数调用一样便宜.
其次,不是使用简单的Haskell类型的参数,如函数的Int和Float参数,现在都是一个巨型的libffi和类型Arg,它对类型系统是不透明的,并且很容易引入细微的错误.
如果你可以在编译时链接C库并向前声明函数,要么使用常规的Haskell FFI(-XForeignFunctionInterface)和/或像c2hs这样的工具,它将使生活变得更加容易.