Suppose we want to be able to call the POSIX directory manipulating functions from Haskell, which has the following C function prototypes:
DIR* opendir(const char* dirname);
struct dirent* readdir(DIR* dirp);
int closedir(DIR* dirp);
void rewinddir(DIR* dirp);
To do this with H/Direct, you'll first have to convert the above C function prototypes into IDL:
module Dir {
// DIR is an abstract type, so we represent DIR* as an
// abstract type here.
interface DIRPtr {};
// POSIX mandates that (struct dirent) just has a member called
// d_name, so we cannot portably define the struct in IDL.
// (the programmer will have to supply a C stub, getEntryName,
// to fish out the name instead). So, we define the directory
// entry type to be abstract too.
interface direntPtr {};
DIRPtr opendir([in,string]char* dirname);
direntPtr readdir([in]DIRPtr dirp);
bool closedir([in]DIRPtr dirp);
void rewinddir([in]DIRPtr dirp);
void getEntryName([in]direntPtr dp,[out,nofree,string]char** pnm);
};
The signatures are all contained within a module declaration,
which simply instructs the IDL compiler to emit the Haskell stubs into
the file Dir.hs. Due to the abstract definition of the DIR
and struct dirent types by POSIX, we don't define them either,
but represent pointers to either type by generic pointers. Things to
note about the function signatures:
opendir takes as an input parameter a character string.
In general, types and parameters can be prefixed with a list of
attributes, enclosed within square brackets.
opendir is a
zero-terminated character string and not just a pointer to a
character, the string attribute is used.
closedir a more informative type in IDL.
DIRPtr and direntPtr types represent
bona fide C pointers, we use the ptr attribute when defining the
types.To generate Haskell stubs for the above functions, invoke the IDL compiler giving the spec as input:
foo% ihc -c dir.idl
Writing Dir.hs.....done
foo%
The generated Haskell file Dir.hs contains stubs that take care
invoking the directory functions, and they have the following Haskell
type signatures:
newtype DIRPtr = ... --abstract
type DirentPtr = ... --abstract
opendir :: String -> IO DIRPtr
readdir :: DIRPtr -> IO DirentPtr
closedir :: DIRPtr -> IO Bool
rewinddir :: DIRPtr -> IO ()
getEntryName :: DirentPtr -> IO String
Figure H/Direct overview
See the H/Direct user's manual for more examples of how the IDL compiler can be used to generate Haskell bindings to external libraries.