>Type signature

7. Type signature

The %fun statement starts a new procedure specification.

Green Card supports two sorts of C procedures: ones that may cause side effects (including I/O), and ones that are guaranteed to be pure functions. The two are distinguished by their type signatures. Side-effecting functions have the result type IO t for some type t. If the programmer specifies any result type other than IO t, Green Card takes this as a promise that the C function is indeed pure, and will generate code that calls unsafePerformIO.

The procedure specification will expand to the definition of a Haskell function, whose name is that given in the %fun statement, with two changes: the longest matching prefix specified with a %prefix statement is removed from the name and the first letter of the remaining function name is changed to lower case (Section 8.3 elaborates). Haskell requires all function names to start with a lower-case letter (upper case would indicate a data constructor), but when the C procedure name begins with an upper case letter it is convenient to still be able to make use of Green Card's automatic fill-in facilities. For example:

%fun OpenWindow :: Int -> IO Window

would expand to a Haskell function openWindow that is implemented by calling the C procedure OpenWindow.

%prefix Win32
%fun Win32OpenWindow :: Int -> IO Window

would also expand to a Haskell function openWindow, but is implemented by calling the C procedure Win32OpenWindow.

7.1. Parameter marshalling

The %call statement tells Green Card how to translate the Haskell parameters into C values. Its syntax is designed to look rather like Haskell pattern matching, and consists of a sequence of zero or more Data Interface Schemes (DISs), one for each (curried) argument in the type signature. For example:

%fun foo :: Float -> (Int,Int) -> String -> IO ()
%call (float x) (int y, int z) (string s)

This %call statement binds the C variables x, y, z, and s, in a similar way that Haskell's pattern-matching binds variables to (parts of) a function's arguments. These bindings are in scope throughout the body and result-marshalling statements.

In the %call statement, ``float'', ``int'', and ``string'' are the names of the DISs that are used to translate between Haskell and C. The names of these DISs are deliberately chosen to be the same as the corresponding Haskell types (apart from changing the initial letter to lower case) so that in many cases, including foo above, Green Card can generate the %call line by itself (Section 8).

In fact there is a fourth DIS hiding in this example, the (_,_) pairing DIS. DISs are discussed in detail in Section 9.

7.2. The body

The body consists of arbitrary C code, beginning with %code. The reason for allowing arbitrary C is that C procedures sometimes have complicated interfaces. They may return results through parameters passed by address, deposit error codes in global variables, require #include'd constants to be passed as parameters, and so on. The body of a Green Card procedure specification allows the programmer to say exactly how to call the procedure, in its native language.

The C code starts a block, and may thus start with declarations that create local variables. For example:

%code int x, y;
%     x = foo( &y, GREY );

Here, x and y are declared as local variables. The local C variables declared at the start of the block scope over the rest of the body and the result-marshalling statements.

The C code may also mention constants from C header files, such as GREY above. Green Card's %#include directive tells it which header files to include (Section 11).

GHC specific: The GHC backend makes a distinction between safe and unsafe external calls: If the external call will cause a garbage collection, you have to call it safely. (A good example of where this is likely to occur is when the external call invokes a Haskell callback.) Green Card supports safe calls in a couple of ways:

  • The command-line option --safe-code will cause the generated code to call all the %code snippets safely.

  • The %safecode declaration is identical to %code except that when generating code for GHC, the code snippet will be called safely. Performing a safe call involves saving away all abstract machine state before performing the call, so it is recommended to use %safecode over --safe-code, since it offers more fine grained control.

7.3. Result marshalling

Functions return their results using a %result statement. Side-effecting functions, ones whose result type is IO t, can also use %fail to specify the failure value.

7.4. Pure functions

The %result statement takes a single DIS that describes how to translate one or more C values back into a single Haskell value. For example:

%fun sin :: Float -> Float
%call (float x)
%code ans = sin(x);
%result (float ans)

As in the case of the %call statement, the ``float'' in the %result statement is the name of a DIS, chosen as before to coincide with the name of the type. A single DIS, ``float'', is used to denote both the translation from Haskell to C and that from C to Haskell, just as a data constructor can be used both to construct a value and to take one apart (in pattern matching).

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 (i.e. %result and %fail).

7.5. Arbitrary C results

In a result-marshalling statement an almost arbitrary C expression, enclosed in braces, can be used in place of a C variable name. The above example could be written more briefly like this: [1]

%fun sin :: Float -> Float
%call (float x)
%result (float {sin(x)})

The C expression can neither have assignments nor nested braces as that could give rise to syntactic ambiguity.

7.6. Side effecting functions

A side effecting function returns a result of type IO t for some type t. The IO monad supports exceptions, so Green Card allows them to be raised.

The result-marshalling statements for a side-effecting call consists of zero or more %fail statements, each of which conditionally raise an exception in the IO monad, followed by a single %result statement that returns successfully in the IO monad.

Just as in Section 7.3, the %result statement gives a single DIS that describes how to construct the result Haskell value, following successful completion of a side-effecting operation. For example:

%fun windowSize :: Window -> IO (Int,Int)
%call (window w)
%code struct WindowInfo wi;
%     GetWindowInfo( w, &wi );
%result (int {wi.x}, int {wi.y})

Here, a pairing DIS is used, with two int DISs inside it. The arguments to the int DISs are C record selections, enclosed in braces; they extract the relevant information from the WindowInfo structure that was filled in by the GetWindowInfo call. [2]

The %fail statement has two fields, each of which is either a C variable, or a C expression enclosed in braces. The first field is a boolean-valued expression that indicates when the call should fail; the second is a (char *) value that indicates what sort of failure occurred. If the boolean is true (i.e. non zero) then the call fails with a userError in the IO monad containing the specified string.

For example:

%fun fopen :: String -> IO FileHandle
%call (string s)
%code f = fopen( s );
%fail {f == NULL} {errstring(errno)}
%result (fileHandle f)

The assumption here is that fopen puts its error code in the global variable errno, and errstring converts that error number to a string.

UserErrors can be caught with catch, but exactly which error occurred must be encoded in the string, and parsed by the error-handling code. This is rather slow, but errors are meant to be exceptional.



It can be written more briefly still by using automatic fill-in, Section 8.


This example also shows one way to interface to C procedures that manipulate structures.