Even after the scope is restricted to designing a foreign-language interface from Haskell to C, the task remains surprisingly tricky. At first, one might think that one could take the C header file describing a C procedure, and generate suitable interface code to make the procedure callable from Haskell.
Alas, there are numerous tiresome details that are simply not expressed by the C procedure prototype in the header file. For example, consider calling a C procedure that opens a file, passing a character string as argument. The C prototype might look like this:
int open( char *filename );
Our goal is to generate code that implements a Haskell procedure with type
open :: String -> IO FileDescriptor
malloc
'ed heap? (But how
will it get deallocated? And malloc
is expensive too.)
NULL
. How is that to be reflected on the host-language
side of the interface? For example, if the documentation for open
told
us that it would do something sensible when called with a NULL
string,
we might like the Haskell type for open
to be
open :: Maybe String -> IO FileDescriptor
so that we can model NULL
by Nothing
.
FileDescriptor
, will presumably
have a Haskell definition such as this:
newtype FileDescriptor = FD Int
The file descriptor returned by open
is just an integer, but
Haskell programmers often use newtype
declarations create new
distinct types isomorphic to existing ones. Now the type system will
prevent, say, an attempt to add one to a FileDescriptor
.
Needless to say, the Haskell result type is not going to be described
in the C header file.
errno
. Somehow this
failure and the details of what went wrong must be reflected into
Haskell's IO
monad.
open
procedure causes a side effect, so it is
appropriate for its type to be in Haskell's IO
monad. Some C
functions really are functions (that is, they have no side effects),
and in this case it makes sense to give them a ``pure'' Haskell type.
For example, the C function sin
should appear to the Haskell
programmer as a function with type
sin :: Float -> Float
in
parameters, which
out
and which are in out
- that is, in what direction do
data pass via a parameter?
None of these details are mentioned in the C header file. Instead, many of them are in the manual page for the procedure, while others (such as parameter lifetimes) may not even be written down at all.