与Python相比,在Haskell中调用c函数

时间:2014-08-02 08:11:50

标签: python haskell ffi

在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

这是真的,有更简单的方法吗?

1 个答案:

答案 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类型的参数,如IntFloat函数的参数现在都在一个巨型的libffi和类型Arg中,它对类型系统是不透明的很容易引入微妙的错误。

如果你可以在编译时链接C库并向前声明函数,要么使用常规的Haskell FFI(-XForeignFunctionInterface)和/或像c2hs这样的工具,它将使生活变得更加容易。