
Richard, I remember having similar problems to you when trying to use the FFI. The following comments are suggestions as to what helps in practice, and not a claim that the situation can't be improved. On 13/05/2009, at 8:40 PM, Richard W.M. Jones wrote:
Specific things would be:
Recommendation to use 'throwDyn' to throw exceptions, yet this function doesn't exist in my version of GHC. In fact, none of the code here:
http://www.haskell.org/haskellwiki/FFICookBook#Raising_and_handling_exceptio...
works in GHC at all, as far as I could tell.
The shifting exceptions story is a PITA. Compatibility is the price of progress.
No good examples available on how to use ForeignPtr. Yet I'd argue that almost any non-trivial modern C library bindings will have some concept of an opaque object, so this is the most vital example. (The examples in RWH ch 17 weren't enough for me).
I'd suggest you download a mature library binding close to what you want to do and ape that. For example: 1. got lots of C structures? look at a GTK binding. 2. got a fairly imperative API? look at a database binding, or HOpenGL. 3. got a fairly pure API? look at a BDD or numerical package binding. and so forth. The FFI itself is intended to be minimal, just enough to do the job. The idea was that extra tools (most prominently hsc2hs and c2hs, historically greencard) would support large bindings. It's funny you say "opaque object". ForeignPtr only handles pointers. In one library I relied on, the opaque objects were represented with ints. It'd be nice to track arbitrary values the way that ForeignPtr tracks C pointers.
I'd really like to know what parameters and return types are permissible for 'foreign import ccall' statements. By trial and error I found out.
Is the FFI spec unclear on this point?
How do I convert to/from booleans?
Can you use the methods of the Enum class?
How do I really use C structures? Real examples, please.
I'd suggest looking into c2hs. Even if you don't use it, the code it generates is quite illuminating, especially how it pushes values between C and Haskell.
How can I free a C string that is returned from a 'caller frees' C function? Does Foreign.Marshall.Alloc.free work for this?
This is tricky. Rather than give you a definite answer, I'd suggest you check with the FFI spec. IIRC in principle the FFI's malloc/free could be distinct from those in C land, but in practice (GHC) they coincide.
Again, reflecting my own inexperience with Haskell, I found 'withCString', 'maybeWith', 'withMany', 'withArray0' etc to be both undocumented and extremely confusing to use.
They're documented in the FFI spec. Granted using them is not necessarily intuitive, which is where looking at existing code might help.
How do I specify a 64 bit int? Using 'Int64#' just causes syntax errors.
Did you look into the Data.Word library?
What's a good emacs editing mode for Haskell code? My emacs thinks Haskell code is LISP ...
There's been a Haskell mode for at least a decade now. It's packaged with every emacs I've used in the past few years. http://www.haskell.org/haskell-mode/ To editorialise a bit, I think the original FFI spec is very clearly written, and the contradictions you allude to lie in fact in the more recent wiki writeups; the Haskell specs are lucid and intended to be usable, and not just by the compiler writers. One last gotcha: be very careful about strictness if you're trying to graft a pure API onto the library. Hope this helps! cheers peter