This chapter describes how user-defined primitives, written in C, can
be linked with Caml code and called from Caml functions.
17.1 |
Overview and compilation information |
|
User primitives are declared in an implementation file or
struct...end module expression using the external keyword:
external name : type = C-function-name
This defines the value name name as a function with type
type that executes by calling the given C function.
For instance, here is how the input primitive is declared in the
standard library module Pervasives:
external input : in_channel -> string -> int -> int -> int
= "input"
Primitives with several arguments are always curried. The C function
does not necessarily have the same name as the ML function.
External functions thus defined can be specified in interface files or
sig...end signatures either as regular values
val name : type
thus hiding their implementation as a C function, or explicitly as
``manifest'' external functions
external name : type = C-function-name
The latter is slightly more efficient, as it allows clients of the
module to call directly the C function instead of going through the
corresponding Caml function.
The arity (number of arguments) of a primitive is automatically
determined from its Caml type in the external declaration, by
counting the number of function arrows in the type. For instance,
input above has arity 4, and the input C function is called with
four arguments. Similarly,
external input2 : in_channel * string * int * int -> int = "input2"
has arity 1, and the input2 C function receives one argument (which
is a quadruple of Caml values).
Type abbreviations are not expanded when determining the arity of a
primitive. For instance,
type int_endo = int -> int
external f : int_endo -> int_endo = "f"
external g : (int -> int) -> (int -> int) = "f"
f has arity 1, but g has arity 2. This allows a primitive to
return a functional value (as in the f example above): just remember
to name the functional return type in a type abbreviation.