user266003
user266003

Reputation:

Calling a c function in Haskell comparing to Python

In Python I can do this:

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

And since I need to convert this type of Python code to Haskell, I wonder can I do the same thing in Haskell? I know I can something like this throug FFI. But it's not exactly what I can do in Python because as far as I am concerned in Haskell I'd have to declare the functions first like the following:

foreign import ccall "my_lib.h some_function"
     some_function :: CDouble -> CDouble

Is that true, is there an easier way?

Upvotes: 4

Views: 214

Answers (1)

Stephen Diehl
Stephen Diehl

Reputation: 8409

The ctypes library in Python is basically a wrapper around the C library libffi which is a library that let's us invoke arbitrary functions in the process's address space given information at runtime instead of compile-time.

The same library can be used in Haskell together with the dynamic linker to achieve the same effect:

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 ()

This isn't ideal for a lot of reasons, and I wouldn't recommend building a large set of bindings like this for the same reason that many Python developers frown on using ctypes for bindings except as a last resort. For one it will have some overhead (roughly the same overhead that ctypes has) for each function call. As compared to a ccall unsafe FFI function from Haskell which has basically no overhead and is as cheap as a native C function call.

Second, instead of having arguments with nice simple Haskell types like Int and Float arguments to functions are now all in a giant libffi sum type Arg that's opaque to the type system and is quite easy to introduce subtle bugs.

If you can link the C library at compile-time and forward declare the functions, either using the regular Haskell FFI ( -XForeignFunctionInterface ) and/or tools like c2hs it will make life much easier.

Upvotes: 4

Related Questions