GreenCard for nhc98


GreenCard is a preprocessor for Haskell which allows Haskell functions to call C. (For the really brave, nhc98 also has the ability to call Haskell code from C using GreenCard to set up the interface.)

A paper (now superseded, see below) published in the Haskell Workshop 97 proceedings describes the design goals, input language, and translation mechanism. GreenCard was supposed to be standard across implementations of Haskell - however the Hugs/ghc version has now diverged somewhat. A new, more flexible but lower-level, primitive FFI is now common to Hugs/ghc and nhc98, and it provides a greater degree of cross-compiler portability than GreenCard. However, GreenCard is still useful for many small tasks, and you may find it is just the right tool for your particular application.

Since the Haskell Workshop paper, several improvements have been made to the input language and DIS macros. GreenCard for nhc98 follows the design agreed with the Glasgow and Hugs implementors (although the Glasgow implementation does not!). Here is the best extant description of GreenCard closely matching the nhc98 version.

There are just a few differences specific to the nhc98 version of the tool.

Some features are not implemented.
%fail is currently ignored silently; %const generates a warning and terminates processing; you cannot yet use named fields (sometimes known as records) in DIS definitions.
Import clause needed.
The code generated by GreenCard uses certain library functions, which may not be visible in the source submitted to GreenCard. To make things easier, we have collected these functions together into a single library module, which should always be imported when you use GreenCard. Simply add the line
        import GreenCard
    
to your source file. GreenCard cannot add this line for you automatically.
Filename conventions.
Source files containing GreenCard directives should have a .gc extension. Both nhc98 and hmake recognise the .gc extension and call GreenCard automatically. When GreenCard is run on a file Module.gc it generates two new files Module_.hs and Module_.c which are processed separately by nhc98 proper and gcc. The end result however is still a single object file called Module.o. (We thought it would be useful to expose the generated files to the user, since any compilation errors will refer to these rather than to the original source (although of course the error must be fixed in the original .gc file)).
Calling Haskell from C.
The Haskell Workshop paper said that "in practice there is zero demand" for calling Haskell from C. We disagree. Using "stable pointers" however, it is possible to go some distance towards providing such a facility. See the document CcallingHaskell and file $NHC98DIR/lib/greencard.h for details. (Note: the newer primitive FFI makes this very much easier - we recommend you use it instead.)
DIS variable scope.
The original paper said: "All the C variables bound in the %call statement, and all those bound in declarations at the start of the body scope over all the result-marshalling statements (%result and %fail)". However, it did not say anything about the scope of variables bound by a %result statement. We say that variables bound in a %result statement are always declared implicitly and scope over the whole body. For example, from the paper:
        %fun foo :: (Age,Age) -> Age
        %call (Age (int x), Age (int y))
        %code r = foo(x,y);
        %result (Age (int r))
    
This example is correct, and indicates that the three variables x y and r are all declared as "int"s prior to the %code body, and scope over the body.
        %fun f :: This -> This
        %call (MkThis (int p) (float q, float r))
        %code int a,b,c;
        %     f( p, q, r, &a, &b, &c);
        %result (this a b c)
    
But this example is incorrect, because the user's definitions of a b and c conflict with the automatic definition from the %result statement. (The variables b and c are "float"s, but the user has tried to declare them as "int"s.

The latest updates to these pages are available on the WWW from http://www.haskell.org/nhc98/

22 December 1999
York Functional Programming Group