Foreword

This document is intended as a reference manual for the Caml Light language. It lists all language constructs, and gives their precise syntax and informal semantics. It is by no means a tutorial introduction to the language: there is not a single example. A good working knowledge of the language, as provided by the companion tutorial Functional programming using Caml Light, is assumed.

No attempt has been made at mathematical rigor: words are employed with their intuitive meaning, without further definition. As a consequence, the typing rules have been left out, by lack of the mathematical framework required to express them, while they are definitely part of a full formal definition of the language. The reader interested in truly formal descriptions of languages from the ML family is referred to The definition of Standard ML and Commentary on Standard ML, by Milner, Tofte and Harper, MIT Press.

Warning

Several implementations of the Caml Light language are available, and they evolve at each release. Consequently, this document carefully distinguishes the language and its implementations. Implementations can provide extra language constructs; moreover, all points left unspecified in this reference manual can be interpreted differently by the implementations. The purpose of this reference manual is to specify those features that all implementations must provide.

Notations

The syntax of the language is given in BNF-like notation. Terminal symbols are set in typewriter font (like this). Non-terminal symbols are set in italic font (like that). Square brackets [...] denote optional components. Curly brackets {...} denotes zero, one or several repetitions of the enclosed components. Curly bracket with a trailing plus sign {...}+ denote one or several repetitions of the enclosed components. Parentheses (...) denote grouping.

Lexical conventions


Lexical conventions

Blanks

The following characters are considered as blanks: space, newline, horizontal tabulation, carriage return, line feed and form feed. Blanks are ignored, but they separate adjacent identifiers, literals and keywords that would otherwise be confused as one single identifier, literal or keyword.

Comments

Comments are introduced by the two characters (*, with no intervening blanks, and terminated by the characters *), with no intervening blanks. Comments are treated as blank characters. Comments do not occur inside string or character literals. Nested comments are correctly handled.

Identifiers

ident:
      letter {letter | 0...9 | _}

letter:
      A...Z | a...z

Identifiers are sequences of letters, digits and _ (the underscore character), starting with a letter. Letters contain at least the 52 lowercase and uppercase letters from the ASCII set. Implementations can recognize as letters other characters from the extended ASCII set. Identifiers cannot contain two adjacent underscore characters (__). Implementation may limit the number of characters of an identifier, but this limit must be above 256 characters. All characters in an identifier are meaningful.

Integer literals

integer-literal:
      [-] {0...9}+
   |  [-] (0x | 0X) {0...9 | A...F | a...f}+
   |  [-] (0o | 0O) {0...7}+
   |  [-] (0b | 0B) {0...1}+

An integer literal is a sequence of one or more digits, optionally preceded by a minus sign. By default, integer literals are in decimal (radix 10). The following prefixes select a different radix:
PrefixRadix
0x, 0Xhexadecimal (radix 16)
0o, 0Ooctal (radix 8)
0b, 0Bbinary (radix 2)
(The initial 0 is the digit zero; the O for octal is the letter O.)

Floating-point literals

float-literal:
      [-] {0...9}+ [. {0...9}] [(e | E) [+ | -] {0...9}+]

Floating-point decimals consist in an integer part, a decimal part and an exponent part. The integer part is a sequence of one or more digits, optionally preceded by a minus sign. The decimal part is a decimal point followed by zero, one or more digits. The exponent part is the character e or E followed by an optional + or - sign, followed by one or more digits. The decimal part or the exponent part can be omitted, but not both to avoid ambiguity with integer literals.

Character literals

char-literal:
      ` regular-char `
   |  ` \ (\ | ` | n | t | b | r) `
   |  ` \ (0...9) (0...9) (0...9) `

Character literals are delimited by ` (backquote) characters. The two backquotes enclose either one character different from ` and \, or one of the escape sequences below:
SequenceCharacter denoted
\\backslash (\)
\`backquote (`)
\nnewline (LF)
\rreturn (CR)
\thorizontal tabulation (TAB)
\bbackspace (BS)
\dddthe character with ASCII code ddd in decimal

String literals

string-literal:
      " {string-character} "

string-character:
      regular-char
   |  \ (\ | " | n | t | b | r)
   |  \ (0...9) (0...9) (0...9)

String literals are delimited by " (double quote) characters. The two double quotes enclose a sequence of either characters different from " and \, or escape sequences from the table below:
SequenceCharacter denoted
\\backslash (\)
\"double quote (")
\nnewline (LF)
\rreturn (CR)
\thorizontal tabulation (TAB)
\bbackspace (BS)
\dddthe character with ASCII code ddd in decimal

Implementations must support string literals up to 2^{16}-1 characters in length (65535 characters).

Keywords

The identifiers below are reserved as keywords, and cannot be employed otherwise:

        and    as     begin       do      done      downto 
        else   end    exception   for     fun       function 
        if     in     let         match   mutable   not 
        of     or     prefix      rec     then      to 
        try    type   value       where   while     with
The following character sequences are also keywords:
        #    !    !=   &    (    )    *    *.   +    +. 
        ,    -    -.   ->   .    .(   /    /.   :    :: 
        :=   ;    ;;   <    <.   <-   <=   <=.  <>   <>. 
        =    =.   ==   >    >.   >=   >=.  @    [    [| 
        ]    ^    _    __   {    |    |]   }    '

Ambiguities

Lexical ambiguities are resolved according to the ``longest match'' rule: when a character sequence can be decomposed into two tokens in several different ways, the decomposition retained is the one with the longest first token.


Global names

Global names

Global names are used to denote value variables, value constructors (constant or non-constant), type constructors, and record labels. Internally, a global name consists of two parts: the name of the defining module (the module name), and the name of the global inside that module (the local name). The two parts of the name must be valid identifiers. Externally, global names have the following syntax:

global-name:
      ident
   |  ident __ ident

The form ident __ ident is called a qualified name. The first identifier is the module name, the second identifier is the local name. The form ident is called an unqualified name. The identifier is the local name; the module name is omitted. The compiler infers this module name following the completion rules given below, therefore transforming the unqualified name into a full global name.

To complete an unqualified identifier, the compiler checks a list of modules, the opened modules, to see if they define a global with the same local name as the unqualified identifier. When one is found, the identifier is completed into the full name of that global. That is, the compiler takes as module name the name of an opened module that defines a global with the same local name as the unqualified identifier. If several modules satisfy this condition, the one that comes first in the list of opened modules is selected.

The list of opened modules always includes the module currently being compiled (checked first). (In the case of a toplevel-based implementation, this is the module where all toplevel definitions are entered.) It also includes a number of standard library modules that provide the initial environment (checked last). In addition, the #open and #close directives can be used to add or remove modules from that list. The modules added with #open are checked after the module currently being compiled, but before the initial standard library modules.

variable:
      global-name
   |  prefix operator-name

operator-name:
      + | - | * | / | mod | +. | -. | *. | /.
   |  @ | ^ | ! | := | = | <> | == | != | !
   |  < | <= | > | <= | <. | <=. | >. | <=.

cconstr:
      global-name
   |  []
   |  ()

ncconstr:
      global-name
   |  prefix ::

typeconstr:
      global-name

label:
      global-name

Depending on the context, global names can stand for global variables (variable), constant value constructors (cconstr), non-constant value constructors (ncconst), type constructors (typeconstr), or record labels (label). For variables and value constructors, special names built with prefix and an operator name are recognized. The tokens [] and () are also recognized as built-in constant constructors (the empty list and the unit value).

The syntax of the language restricts labels and type constructors to appear in certain positions, where no other kind of global names are accepted. Hence labels and type constructors have their own name spaces. Value constructors and value variables live in the same name space: a global name in value position is interpreted as a value constructor if it appears in the scope of a type declaration defining that constructor; otherwise, the global name is taken to be a value variable. For value constructors, the type declaration determines whether a constructor is constant or not.


Values

Values

This section describes the kinds of values that are manipulated by Caml Light programs.

Base values

Integer numbers

Integer values are integer numbers from -2^{30} to 2^{30}-1, that is -1073741824 to 1073741823. Implementations may support a wider range of integer values.

Floating-point numbers

Floating-point values are numbers in floating-point representation. Everything about floating-point values is implementation-dependent, including the range of representable numbers, the number of significant digits, and the way floating-point results are rounded.

Characters

Character values are represented as 8-bit integers between 0 and 255. Character codes between 0 and 127 are interpreted following the ASCII standard. The interpretation of character codes between 128 and 255 is implementation-dependent.

Character strings

String values are finite sequences of characters. Implementations must support strings up to 2^{16}-1 characters in length (65535 characters). Implementations may support longer strings.

Tuples

Tuples of values are written (v_1, ..., v_n), standing for the n-tuple of values v_1 to v_n. Tuples of up to 2^{14}-1 elements (16383 elements) must be supported, though implementations may support tuples with more elements.

Records

Record values are labeled tuples of values. The record value written { label_1 = v_1; ...; label_n = v_n } associates the value v_i to the record label label_i, for i = 1 ... n. Records with up to 2^{14}-1 fields (16383 fields) must be supported, though implementations may support records with more fields.

Arrays

Arrays are finite, variable-sized sequences of values of the same type. Arrays of length up to 2^{14}-1 (16383 elements) must be supported, though implementations may support larger arrays.

Variant values

Variant values are either a constant constructor, or a pair of a non-constant constructor and a value. The former case is written cconstr; the latter case is written ncconstr(v), where v is said to be the argument of the non-constant constructor ncconstr.

The following constants are treated like built-in constant constructors:
ConstantConstructor
falsethe boolean false
truethe boolean true
()the ``unit'' value
[]the empty list

Functions

Functional values are mappings from values to values.


Type expressions

Type expressions

typexpr:
      ' ident
   |  ( typexpr )
   |  typexpr -> typexpr
   |  typexpr {* typexpr}+
   |  typeconstr
   |  typexpr typeconstr
   |  ( typexpr {, typexpr} ) typeconstr

The table below shows the relative precedences and associativity of operators and non-closed type constructions. The constructions with higher precedences come first.
OperatorAssociativity
Type constructor application--
*--
->right

Type expressions denote types in definitions of data types as well as in type constraints over patterns and expressions.

Type variables

The type expression ' ident stands for the type variable named ident. In data type definitions, type variables are names for the data type parameters. In type constraints, they represent unspecified types that can be instantiated by any type to satisfy the type constraint.

Parenthesized types

The type expression ( typexpr ) denotes the same type as typexpr.

Function types

The type expression typexpr1 -> typexpr2 denotes the type of functions mapping arguments of type typexpr1 to results of type typexpr2.

Tuple types

The type expression typexpr1 *...* typexprn denotes the type of tuples whose elements belong to types typexpr1,...typexprn respectively.

Constructed types

Type constructors with no parameter, as in typeconstr, are type expressions.

The type expression typexpr typeconstr, where typeconstr is a type constructor with one parameter, denotes the application of the unary type constructor typeconstr to the type typexpr.

The type expression (typexpr1,...,typexprn) typeconstr, where typeconstr is a type constructor with n parameters, denotes the application of the n-ary type constructor typeconstr to the types typexpr1 through typexprn.


Constants

Constants

constant:
      integer-literal
   |  float-literal
   |  char-literal
   |  string-literal
   |  cconstr

The syntactic class of constants comprises literals from the four base types (integers, floating-point numbers, characters, character strings), and constant constructors. Patterns


Patterns

pattern:
      ident
   |  _
   |  pattern as ident
   |  ( pattern )
   |  ( pattern : typexpr )
   |  pattern | pattern
   |  constant
   |  ncconstr pattern
   |  pattern , pattern {, pattern}
   |  { label = pattern {; label = pattern} }
   |  [ ]
   |  [ pattern {; pattern} ]
   |  pattern :: pattern

The table below shows the relative precedences and associativity of operators and non-closed pattern constructions. The constructions with higher precedences come first.
OperatorAssociativity
Constructor application--
::right
,--
|left
as--

Patterns are templates that allow selecting data structures of a given shape, and binding identifiers to components of the data structure. This selection operation is called pattern matching; its outcome is either ``this value does not match this pattern'', or ``this value matches this pattern, resulting in the following bindings of identifiers to values''.

Variable patterns

A pattern that consists in an identifier matches any value, binding the identifier to the value. The pattern _ also matches any value, but does not bind any identifier.

Alias patterns

The pattern pattern1 as ident matches the same values as pattern1. If the matching against pattern1 is successful, the identifier ident is bound to the matched value, in addition to the bindings performed by the matching against pattern1.

Parenthesized patterns

The pattern ( pattern1 ) matches the same values as pattern1. A type constraint can appear in a parenthesized patterns, as in ( pattern1 : typexpr ). This constraint forces the type of pattern1 to be compatible with type.

``Or'' patterns

The pattern pattern1 | pattern2 represents the logical ``or'' of the two patterns pattern1 and pattern2. A value matches pattern1 | pattern2 either if it matches pattern1 or if it matches pattern2. The two sub-patterns pattern1 and pattern2 must contain no identifiers. Hence no bindings are returned by matching against an ``or'' pattern.

Constant patterns

A pattern consisting in a constant matches the values that are equal to this constant.

Variant patterns

The pattern ncconstr pattern1 matches all variants whose constructor is equal to ncconstr, and whose argument matches pattern1.

The pattern pattern1 :: pattern2 matches non-empty lists whose heads match pattern1, and whose tails match pattern2. This pattern behaves like prefix :: ( pattern1 , pattern2 ).

The pattern [ pattern1 ;...; patternn ] matches lists of length n whose elements match pattern1 ... patternn, respectively. This pattern behaves like pattern1 ::...:: patternn :: [].

Tuple patterns

The pattern pattern1 ,..., patternn matches n-tuples whose components match the patterns pattern1 through patternn. That is, the pattern matches the tuple values (v1,...,vn) such that patterni matches vi for i = 1, ..., n.

Record patterns

The pattern { label1 = pattern1 ;...; labeln = patternn } matches records that define at least the labels label1 through labeln, and such that the value associated to labeli match the pattern patterni, for i = 1, ..., n. The record value can define more labels than label1 ... labeln; the values associated to these extra labels are not taken into account for matching.


Expressions

Expressions

expr:
      ident
   |  variable
   |  constant
   |  ( expr )
   |  begin expr end
   |  ( expr : typexpr )
   |  expr , expr {, expr}
   |  ncconstr expr
   |  expr :: expr
   |  [ expr {; expr} ]
   |  [| expr {; expr} |]
   |  { label = expr {; label = expr} }
   |  expr expr
   |  prefix-op expr
   |  expr infix-op expr
   |  expr . label
   |  expr . label <- expr
   |  expr .( expr )
   |  expr .( expr ) <- expr
   |  expr & expr
   |  expr or expr
   |  if expr then expr [else expr]
   |  while expr do expr done
   |  for ident = expr (to | downto) expr do expr done
   |  expr ; expr
   |  match expr with simple-matching
   |  fun multiple-matching
   |  function simple-matching
   |  try expr with simple-matching
   |  let [rec] let-binding {and let-binding} in expr

simple-matching:
      pattern -> expr {| pattern -> expr}

multiple-matching:
      pattern-list -> expr {| pattern-list -> expr}

pattern-list:
      pattern {pattern}

let-binding:
      pattern = expr
   |  variable pattern-list = expr

prefix-op:
      - | -. | !

infix-op:
      + | - | * | / | mod | +. | -. | *. | /. | ** | @ | ^ | ! | :=
   |  = | <> | == | != | < | <= | > | >= | <. | <=. | >. | >=.

The table below shows the relative precedences and associativity of operators and non-closed constructions. The constructions with higher precedence come first.
Construction or operatorAssociativity
!--
. .(--
function applicationleft
constructor application--
- -. (prefix)--
**right
modleft
* *. / /.left
+ +. - -.left
::right
@ ^right
comparisons (= == < etc.)left
not--
&left
orleft
,--
<- :=right
if--
;right
let match fun function try--

Simple expressions

Constants

Expressions consisting in a constant evaluate to this constant.

Variables

Expressions consisting in a variable evaluate to the value bound to this variable in the current evaluation environment. The variable can be either a qualified identifier or a simple identifier. Qualified identifiers always denote global variables. Simple identifiers denote either a local variable, if the identifier is locally bound, or a global variable, whose full name is obtained by qualifying the simple identifier, as described in section 3.3.

Parenthesized expressions

The expressions ( expr ) and begin expr end have the same value as expr. Both constructs are semantically equivalent, but it is good style to use begin...end inside control structures:

        if ... then begin ... ; ... end else begin ... ; ... end
and (...) for the other grouping situations.

Parenthesized expressions can contain a type constraint, as in ( expr : type ). This constraint forces the type of expr to be compatible with type.

Function abstraction

The most general form of function abstraction is:

fun pattern11 ... pattern1M -> expr1
  | ...
  | patternN1 ... patternNM -> exprN
This expression evaluates to a functional value with m curried arguments. When this function is applied to m values v1 ... vm, the values are matched against each pattern row patterni1...patternim for i from 1 to n. If one of these matchings succeeds, that is if the value vj matches the pattern patternij for all j = 1, ..., m, then the expression expri associated to the selected pattern row is evaluated, and its value becomes the value of the function application. The evaluation of expri takes place in an environment enriched by the bindings performed during the matching.

If several pattern rows match the arguments, the one that occurs first in the function definition is selected. If none of the pattern rows matches the argument, the exception Match_failure is raised.

If the function above is applied to less than m arguments, a functional value is returned, that represents the partial application of the function to the arguments provided. This partial application is a function that, when applied to the remaining arguments, matches all arguments against the pattern rows as described above. Matching does not start until all m arguments have been provided to the function; hence, partial applications of the function to less than m arguments never raise Match_failure.

All pattern rows in the function body must contain the same number of patterns. A variable must not be bound more than once in one pattern row.

Functions with only one argument can be defined with the function keyword instead of fun:

function pattern1 -> expr1
       | ...
       | patternN -> exprN
The function thus defined behaves exactly as described above. The only difference between the two forms of function definition is how a parsing ambiguity is resolved. The two forms cconstr pattern (two patterns in a row) and ncconstr pattern (one pattern) cannot be distinguished syntactically. Function definitions introduced by fun resolve the ambiguity to the former form; function definitions introduced by function resolve it to the latter form (the former form makes no sense in this case).

Function application

Function application is denoted by juxtaposition of expressions. The expression expr1 expr2...exprn evaluates the expressions expr1 to exprn. The expression expr1 must evaluate to a functional value, which is then applied to the values of expr2,...,exprn. The order in which the expressions expr1,...,exprn are evaluated is not specified.

Local definitions

The let and let rec constructs bind variables locally. The construct

let pattern1 = expr1 and...and patternn = exprn in expr
evaluates expr1...exprn in some unspecified order, then matches their values against the patterns pattern1...patternn. If the matchings succeed, expr is evaluated in the environment enriched by the bindings performed during matching, and the value of expr is returned as the value of the whole let expression. If one of the matchings fails, the exception Match_failure is raised.

An alternate syntax is provided to bind variables to functional values: instead of writing

ident = fun pattern1...patternm -> expr
in a let expression, one may instead write
ident pattern1...patternm = expr
Both forms bind ident to the curried function with m arguments and only one case,
pattern1...patternm -> expr.

Recursive definitions of variables are introduced by let rec:

let rec pattern1 = expr1 and...and patternn = exprn in expr
The only difference with the let construct described above is that the bindings of variables to values performed by the pattern-matching are considered already performed when the expressions expr1 to exprn are evaluated. That is, the expressions expr1 to exprn can reference identifiers that are bound by one of the patterns pattern1,...,patternn, and expect them to have the same value as in expr, the body of the let rec construct.

The recursive definition is guaranteed to behave as described above if the expressions expr1 to exprn are function definitions (fun... or function...), and the patterns pattern1...patternn consist in a single variable, as in:

let rec ident1 = fun...and...and identn = fun...in expr
This defines ident1...identn as mutually recursive functions local to expr. The behavior of other forms of let rec definitions is implementation-dependent.

Control constructs

Sequence

The expression expr1 ; expr2 evaluates expr1 first, then expr2, and returns the value of expr2.

Conditional

The expression if expr1 then expr2 else expr3 evaluates to the value of expr2 if expr1 evaluates to the boolean true, and to the value of expr3 if expr1 evaluates to the boolean false.

The else expr3 part can be omitted, in which case it defaults to else ().

Case expression

The expression

match expr with
      pattern1 -> expr1
    | ...
    | patternN -> exprN
matches the value of expr against the patterns pattern1 to patternn. If the matching against patterni succeeds, the associated expression expri is evaluated, and its value becomes the value of the whole match expression. The evaluation of expri takes place in an environment enriched by the bindings performed during matching. If several patterns match the value of expr, the one that occurs first in the match expression is selected. If none of the patterns match the value of expr, the exception Match_failure is raised.

Boolean operators

The expression expr1 & expr2 evaluates to true if both expr1 and expr2 evaluate to true; otherwise, it evaluates to false. The first component, expr1, is evaluated first. The second component, expr2, is not evaluated if the first component evaluates to false. Hence, the expression expr1 & expr2 behaves exactly as

if expr1 then expr2 else false.

The expression expr1 or expr2 evaluates to true if one of expr1 and expr2 evaluates to true; otherwise, it evaluates to false. The first component, expr1, is evaluated first. The second component, expr2, is not evaluated if the first component evaluates to true. Hence, the expression expr1 or expr2 behaves exactly as

if expr1 then true else expr2.

Loops

The expression while expr1 do expr2 done repeatedly evaluates expr2 while expr1 evaluates to true. The loop condition expr1 is evaluated and tested at the beginning of each iteration. The whole while...done expression evaluates to the unit value ().

The expression for ident = expr1 to expr2 do expr3 done first evaluates the expressions expr1 and expr2 (the boundaries) into integer values n and p. Then, the loop body expr3 is repeatedly evaluated in an environment where the local variable named ident is successively bound to the values n, n+1, \ldots, p-1, p. The loop body is never evaluated if n > p.

The expression for ident = expr1 downto expr2 do expr3 done first evaluates the expressions expr1 and expr2 (the boundaries) into integer values n and p. Then, the loop body expr3 is repeatedly evaluated in an environment where the local variable named ident is successively bound to the values n, n-1, \ldots, p+1, p. The loop body is never evaluated if n < p.

In both cases, the whole for expression evaluates to the unit value ().

Exception handling

The expression

try  expr
with pattern1 -> expr1
    | ...
    | patternN -> exprN
evaluates the expression expr and returns its value if the evaluation of expr does not raise any exception. If the evaluation of expr raises an exception, the exception value is matched against the patterns pattern1 to patternn. If the matching against patterni succeeds, the associated expression expri is evaluated, and its value becomes the value of the whole try expression. The evaluation of expri takes place in an environment enriched by the bindings performed during matching. If several patterns match the value of expr, the one that occurs first in the try expression is selected. If none of the patterns matches the value of expr, the exception value is raised again, thereby transparently ``passing through'' the try construct.

Operations on data structures

Products

The expression expr1 ,..., exprn evaluates to the n-tuple of the values of expressions expr1 to exprn. The evaluation order for the subexpressions is not specified.

Variants

The expression ncconstr expr evaluates to the variant value whose constructor is ncconstr, and whose argument is the value of expr.

For lists, some syntactic sugar is provided. The expression expr1 :: expr2 stands for the constructor prefix :: applied to the argument ( expr1 , expr2 ), and therefore evaluates to the list whose head is the value of expr1 and whose tail is the value of expr2. The expression [ expr1 ;...; exprn ] is equivalent to expr1 ::...:: exprn :: [], and therefore evaluates to the list whose elements are the values of expr1 to exprn.

Records

The expression { label1 = expr1 ;...; labeln = exprn } evaluates to the record value { label1 = v1 ;...; labeln = vn }, where vi is the value of expri for i = 1, ..., n. The labels label1 to labeln must all belong to the same record types; all labels belonging to this record type must appear exactly once in the record expression, though they can appear in any order. The order in which expr1 to exprn are evaluated is not specified.

The expression expr1 . label evaluates expr1 to a record value, and returns the value associated to label in this record value.

The expression expr1 . label <- expr2 evaluates expr1 to a record value, which is then modified in-place by replacing the value associated to label in this record by the value of expr2. This operation is permitted only if label has been declared mutable in the definition of the record type. The whole expression expr1 . label <- expr2 evaluates to the unit value ().

Arrays

The expression [| expr1 ;...; exprn |] evaluates to a n-element array, whose elements are initialized with the values of expr1 to exprn respectively. The order in which these expressions are evaluated is unspecified.

The expression expr1 .( expr2 ) is equivalent to the application vect_item expr1 expr2. In the initial environment, the identifier vect_item resolves to a built-in function that returns the value of element number expr2 in the array denoted by expr1. The first element has number 0; the last element has number n-1, where n is the size of the array. The exception Invalid_argument is raised if the access is out of bounds.

The expression expr1 .( expr2 ) <- expr3 is equivalent to vect_assign expr1 expr2 expr3. In the initial environment, the identifier vect_assign resolves to a built-in function that modifies in-place the array denoted by expr1, replacing element number expr2 by the value of expr3. The exception Invalid_argument is raised if the access is out of bounds. The built-in function returns (). Hence, the whole expression expr1 .( expr2 ) <- expr3 evaluates to the unit value ().

This behavior of the two constructs expr1 .( expr2 ) and expr1 .( expr2 ) <- expr3 may change if the meaning of the identifiers vect_item and vect_assign is changed, either by redefinition or by modification of the list of opened modules. See the discussion below on operators.

Operators

The operators written infix-op in the grammar above can appear in infix position (between two expressions). The operators written prefix-op in the grammar above can appear in prefix position (in front of an expression).

The expression prefix-op expr is interpreted as the application ident expr, where ident is the identifier associated to the operator prefix-op in the table below. Similarly, the expression expr1 infix-op expr2 is interpreted as the application ident expr1 expr2, where ident is the identifier associated to the operator infix-op in the table below. The identifiers written ident above are then evaluated following the rules in section 3.8. In the initial environment, they evaluate to built-in functions whose behavior is described in the table. The behavior of the constructions prefix-op expr and expr1 infix-op expr2 may change if the meaning of the identifiers associated to prefix-op or infix-op is changed, either by redefinition of the identifiers, or by modification of the list of opened modules, through the #open and #close directives.

OperatorAssociated identBehavior in the default environment
+prefix +Integer addition.
- (infix)prefix -Integer subtraction.
- (prefix)minusInteger negation.
*prefix *Integer multiplication.
/prefix /Integer division. Raise Division_by_zero if second argument is zero. The result is unspecified if either argument is negative.
modprefix modInteger modulus. Raise Division_by_zero if second argument is zero. The result is unspecified if either argument is negative.
+.prefix +.Floating-point addition.
-. (infix)prefix -.Floating-point subtraction.
-. (prefix)minus_floatFloating-point negation.
*.prefix *.Floating-point multiplication.
/.prefix /.Floating-point division. Raise Division_by_zero if second argument is zero.
**prefix **Floating-point exponentiation.
@ prefix @List concatenation.
^ prefix ^String concatenation.
! prefix !Dereferencing (return the current contents of a reference).
:=prefix :=Reference assignment (update the reference given as first argument with the value of the second argument).
= prefix =Structural equality test.
<> prefix <>Structural inequality test.
== prefix ==Physical equality test.
!= prefix !=Physical inequality test.
< prefix <Test ``less than'' on integers.
<= prefix <=Test ``less than or equal '' on integers.
> prefix >Test ``greater than'' on integers.
>= prefix >=Test ``greater than or equal'' on integers.
<. prefix <.Test ``less than'' on floating-point numbers.
<=. prefix <=.Test ``less than or equal '' on floating-point numbers.
>. prefix >.Test ``greater than'' on floating-point numbers.
>=. prefix >=.Test ``greater than or equal'' on floating-point numbers.

The behavior of the +, -, *, /, mod, +., -., *. or /. operators is unspecified if the result falls outside of the range of representable integers or floating-point numbers, respectively. See chapter 14 for a more precise description of the behavior of the operators above.


Global definitions

Global definitions

This section describes the constructs that bind global identifiers (value variables, value constructors, type constructors, record labels).

Type definitions

type-definition:
      type typedef {and typedef}

typedef:
      type-params ident = constr-decl {| constr-decl}
   |  type-params ident = { label-decl {; label-decl} }
   |  type-params ident == typexpr
   |  type-params ident

type-params:
      nothing
   |  ' ident
   |  ( ' ident {, ' ident} )

constr-decl:
      ident
   |  ident of typexpr

label-decl:
      ident : typexpr
   |  mutable ident : typexpr

Type definitions bind type constructors to data types: either variant types, record types, type abbreviations, or abstract data types.

Type definitions are introduced by the type keyword, and consist in one or several simple definitions, possibly mutually recursive, separated by the and keyword. Each simple definition defines one type constructor.

A simple definition consists in an identifier, possibly preceded by one or several type parameters, and followed by a data type description. The identifier is the local name of the type constructor being defined. (The module name for this type constructor is the name of the module being compiled.) The optional type parameters are either one type variable ' ident, for type constructors with one parameter, or a list of type variables (' ident1,...,' identn), for type constructors with several parameters. These type parameters can appear in the type expressions of the right-hand side of the definition.

Variant types

The type definition typeparams ident = constr-decl1 |...| constr-decln defines a variant type. The constructor declarations constr-decl1,...,constr-decln describe the constructors associated to this variant type. The constructor declaration ident of typexpr declares the local name ident (in the module being compiled) as a non-constant constructor, whose argument has type typexpr. The constructor declaration ident declares the local name ident (in the module being compiled) as a constant constructor.

Record types

The type definition typeparams ident = { label-decl1 ;...; label-decln } defines a record type. The label declarations label-decl1,...,label-decln describe the labels associated to this record type. The label declaration ident : typexpr declares the local name ident in the module being compiled as a label, whose argument has type typexpr. The label declaration mutable ident : typexpr behaves similarly; in addition, it allows physical modification over the argument to this label.

Type abbreviations

The type definition typeparams ident == typexpr defines the type constructor ident as an abbreviation for the type expression typexpr.

Abstract types

The type definition typeparams ident defines ident as an abstract type. When appearing in a module interface, this definition allows exporting a type constructor while hiding how it is represented in the module implementation.

typeparams ident mutable behaves similarly, but makes it apparent that the type ident is implemented by a data type accepting physical

Exception definitions

exception-definition:
      exception constr-decl {and constr-decl}

Exception definitions add new constructors to the built-in variant type exn of exception values. The constructors are declared as for a definition of a variant type.


Directives

Directives

directive:
      # open string
   |  # close string
   |  # ident string

Directives control the behavior of the compiler. They apply to the remainder of the current compilation unit.

The two directives #open and #close modify the list of opened modules, that the compiler uses to complete unqualified identifiers, as described in section 3.3. The directive #open string adds the module whose name is given by the string constant string to the list of opened modules, in first position. The directive #close string removes the first occurrence of the module whose name is given by the string constant string from the list of opened modules.

Implementations can provide other directives, provided they follow the syntax # ident string, where ident is the name of the directive, and the string constant string is the argument to the directive. The behavior of these additional directives is implementation-dependent. Module implementations


Module implementations

implementation:
      {impl-phrase ;;}

impl-phrase:
      expr
   |  value-definition
   |  type-definition
   |  exception-definition
   |  directive

value-definition:
      let [rec] let-binding {and let-binding}

A module implementation consists in a sequence of implementation phrases, terminated by double semicolons. An implementation phrase is either an expression, a value definition, a type or exception definition, or a directive. At run-time, implementation phrases are evaluated sequentially, in the order in which they appear in the module implementation.

Implementation phrases consisting in an expression are evaluated for their side-effects.

Value definitions bind global value variables in the same way as a let...in... expression binds local variables. The expressions are evaluated, and their values are matched against the left-hand sides of the = sides, as explained in section 3.8. If the matching succeeds, the bindings of identifiers to values performed during matching are interpreted as bindings to the global value variables whose local name is the identifier, and whose module name is the name of the module. If the matching fails, the exception Match_failure is raised. The scope of these bindings is the phrases that follow the value definition in the module implementation.

Type and exception definitions introduce type constructors, variant constructors and record labels as described in sections 3.9 and 3.9. The scope of these definitions is the phrases that follow the value definition in the module implementation. The evaluation of an implementation phrase consisting in a type or exception definition produces no effect at run-time.

Directives modify the behavior of the compiler on the subsequent phrases of the module implementation, as described in section 3.10. The evaluation of an implementation phrase consisting in a directive produces no effect at run-time. Directives apply only to the module currently being compiled; in particular, they have no effect on other modules that refer to globals exported by the module being compiled.


Module interfaces

Module interfaces

interface:
      {intf-phrase ;;}

intf-phrase:
      value-declaration
   |  type-definition
   |  exception-definition
   |  directive

value-declaration:
      value ident : typexpr {and ident : typexpr}

Module interfaces declare the global objects (value variables, type constructors, variant constructors, record labels) that a module exports, that is, makes available to other modules. Other modules can refer to these globals using qualified identifiers or the #open directive, as explained in section 3.3.

A module interface consists in a sequence of interface phrases, terminated by double semicolons. An interface phrase is either a value declaration, a type definition, an exception definition, or a directive.

Value declarations declare global value variables that are exported by the module implementation, and the types with which they are exported. The module implementation must define these variables, with types at least as general as the types declared in the interface. The scope of the bindings for these global variables extends from the module implementation itself to all modules that refer to those variables.

Type or exception definitions introduce type constructors, variant constructors and record labels as described in sections 3.9 and 3.9. Exception definitions and type definitions that are not abstract type declarations also take effect in the module implementation; that is, the type constructors, variant constructors and record labels they define are considered bound on entrance to the module implementation, and can be referred to by the implementation phrases. Type definitions that are not abstract type declarations must not be redefined in the module implementation. In contrast, the type constructors that are declared abstract in a module interface must be defined in the module implementation, with the same names.

Directives modify the behavior of the compiler on the subsequent phrases of the module interface, as described in section 3.10. Directives apply only to the interface currently being compiled; in particular, they have no effect on other modules that refer to globals exported by the interface being compiled.