[Haskell-cafe] [ANN] Haskell FFI Tutorial
donn at avvanta.com
Wed Nov 12 07:37:49 UTC 2014
quoth Evan Laforge <qdunkan at gmail.com>
> Anyway, in the big picture, I think hsc2hs is just too low level. We
> shouldn't be having to manually poke structs at all, and it's
> fundamentally dangerous even if you use all C types because there's no
> typechecking. Nothing will help you when someone updates the struct
> and forgets to update the Storable instance. If I were starting again
> (or advising someone who was starting from scratch), I'd try really
> hard to find something that directly generates marshalling code from
> the .h file, perhaps c2hs can do that.
I'm not up for generating anything directly from a .h file, but
just for fun I put a little time today into an hsc alternative
with a little more type safety.
It works to a certain extent with integral types, because I can
determine the size of the C field and assign an appropriate Haskell
foreign integral type. I used it to generate a module for struct termios,
for which I've been using hsc2hs, and it did better than hsc2hs in
an unexpected way - hsc2hs #type maps "unsigned long" to "Word32",
but on MacOS X the field size is 8 bytes.
Then I make a raft of peek and poke functions that take the native
Haskell values that you specify, and convert them to the appropriate
foreign types. This is based on a descriptor file where you specify
the fields you want to use, your Haskell name and type for each, and
whether it's integral or whatever.
Integral or whatever is where the joy leaks out of the concept, though.
I'd bet a quarter that at least one in every four .hsc files contains
some custom peeking and poking for a struct field, stuff you'd never
anticipate. Full support for all types seems like a nearly unbounded
hsc2hs could do essentially what I'm talking about, if it could tell
you the size of a field. Then you could declare the foreign types like
termiosC_lflag :: (#appendfieldsize Word struct termios, c_lflag)
which would expand to termiosC_lflag :: Word64
(fieldsize would be sizeof(x->c_lflag) * 8)
This would give us foreign types based on the C declaration.
You'd have to do the conversions yourself where you want to use
native types, in this scenario.
More information about the Haskell-Cafe