Primitive FFI in nhc98

The nhc98 compiler contains an implementation of the standard foreign function interface that is also available in Hugs and ghc. The most recent released version of nhc98 implements the latest standard syntax for foreign function declarations, as specified at:

The FFI standard specifies both the basic mechanism as a language extension, and a layer of libraries. The libraries contain many useful datatypes and access functions, for instance to manage memory storage in the foreign language. nhc98's implementation includes two versions of these libraries: nhc98's internal FFI library, and the standard portable Foreign libraries. The latter collection departs from the official standard only in the use of the hierarchical module namespace instead of the official flat namespace.

Compliance notes

  • Supported calling conventions are: ccall, noproto, and cast. (The latter two are non-standard, see below.) Unsupported calling conventions are: stdcall, jvm, dotnet, cplusplus.
  • foreign import "wrapper" is not yet supported.
  • The annotation unsafe has no special meaning in nhc98; it is purely a speed optimisation for ghc.
  • A foreign export specification is treated as the actual type signature for the exported function. You are not allowed a second (possibly more general) type signature.
  • Hence, you cannot foreign export any function that requires a class dictionary.


  • Two non-standard calling conventions are provided. cast indicates that an arity-1 foreign import is only being used for its C type-cast, and hence eliminates some runtime overheads. For example,
      foreign import cast floatToDouble :: Float -> Double 
    The calling convention noproto is essentially the same as ccall but tells the compiler not to generate a C function prototype for the external function. For example,
      foreign import sin noproto :: Float -> Float 
    eliminates the normal generation of
      extern float sin (float); 
    for occasions when such a declaration might conflict with an external declaration. (Note, if you mention a header file in the foreign entity description, this has the same effect as noproto - i.e. the header file declaration is used in preference to generating a prototype.)
  • The set of primitive types allowed across the FFI is slightly larger in nhc98 than the standard allowed set: we allow PackedString to be passed - these are genuine null-terminated C-style strings. Used as a result type, the string is copied into the Haskell heap (allowing the original pointer to be freed safely); used as an argument type, a pointer to the heap-allocated string is passed to C (i.e. do not free it!). However, we recommend you use the standard type Foreign.C.String instead - it is more portable.
  • Additionally, we allow any non-primitive datatype to be passed across the FFI (but give a Warning for each one) as a heap pointer. This feature should only be used by serious implementers, because any foreign code manipulating non-primitive data must use nhc98's internal heap format.

Recent Changes

  • In a foreign import specification, the specification of a C header file or library in the "external entity" string was previously ignored. nhc98 now generates #include for these header files. Where a header file is specified, the compiler does not generate its own prototype for the foreign function, as if the 'noproto' calling convention had been used.
  • foreign import "dynamic" is now fully supported.

The latest updates to these pages are available on the WWW from

This page last modified: 16th June 2003
York Functional Programming Group