7.7 Expressions

expr::=value-path
constant
( expr )
begin expr end
( expr : typexpr )
expr {, expr}+
constr expr
`tag-name expr
expr :: expr
[ expr { ; expr } [;] ]
[| expr { ; expr } [;] |]
{ field [: typexpr] [= expr] { ; field [: typexpr] [= expr] } [;] }
{ expr with field [: typexpr] [= expr] { ; field [: typexpr] [= expr] } [;] }
expr { argument }+
prefix-symbol expr
- expr
-. expr
expr infix-op expr
expr . field
expr . field <- expr
expr .( expr )
expr .( expr ) <- expr
expr .[ expr ]
expr .[ expr ] <- expr
if expr then expr [ else expr ]
while expr do expr done
for value-name = expr ( to ∣ downto ) expr do expr done
expr ; expr
match expr with pattern-matching
function pattern-matching
fun { parameter }+ [ : typexpr ] -> expr
try expr with pattern-matching
let [rec] let-binding { and let-binding } in expr
let exception constr-decl in expr
new class-path
object class-body end
expr # method-name
inst-var-name
inst-var-name <- expr
( expr :> typexpr )
( expr : typexpr :> typexpr )
{< [ inst-var-name [= expr] { ; inst-var-name [= expr] } [;] ] >}
assert expr
lazy expr
let module module-name { ( module-name : module-type ) } [ : module-type ] = module-expr in expr
let open module-path in expr
module-path .( expr )
module-path .[ expr ]
module-path .[| expr |]
module-path .{ expr }
module-path .{< expr >}
argument::=expr
~ label-name
~ label-name : expr
? label-name
? label-name : expr
pattern-matching::=[ | ] pattern [when expr] -> expr { | pattern [when expr] -> expr }
let-binding::=pattern = expr
value-name { parameter } [: typexpr] [:> typexpr] = expr
value-name : poly-typexpr = expr
parameter::=pattern
~ label-name
~ ( label-name [: typexpr] )
~ label-name : pattern
? label-name
? ( label-name [: typexpr] [= expr] )
? label-name : pattern
? label-name : ( pattern [: typexpr] [= expr] )

See also the following language extensions:first-class modules,overriding in open statements,syntax for Bigarray access,attributes,extension nodes andextended indexing operators.

7.7.1 Precedence and associativity

The table below shows the relative precedences and associativity ofoperators and non-closed constructions. The constructions with higherprecedence come first. For infix and prefix symbols, we write“…” to mean “any symbol starting with ”.

Construction or operatorAssociativity
prefix-symbol
. .( .[ .{ (see section 8.12)
#…left
function application, constructor application, tagapplication, assert,lazyleft
- -. (prefix)
*… lsl lsr asrright
… /… %… mod land lor lxorleft
+… -…left
::right
@… ^…right
=… <… >… |… &… $… !=left
& &&right
or ||right
,
<- :=right
if
;right
let match fun function try

7.7.2 Basic expressions

Constants

An expression consisting in a constant evaluates to this constant.

Value paths

An expression consisting in an access path evaluates to the value bound tothis path in the current evaluation environment. The path canbe either a value name or an access path to a value component of a module.

Parenthesized expressions

The expressions (expr) and beginexprend have the samevalue as expr. The two constructs are semantically equivalent, but itis good style to use begin … end inside control structures:

  1. if then begin ; end else begin ; end

and ( … ) for the other grouping situations.

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

Parenthesized expressions can also contain coercions(expr [:typexpr] :> typexpr) (seesubsection 7.7.7 below).

Function application

Function application is denoted by juxtaposition of (possibly labeled)expressions. The expression expr argument1argumentnevaluates the expression expr and those appearing in argument1to argumentn. The expression expr must evaluate to afunctional value f, which is then applied to the values ofargument1, …, argumentn.

The order in which the expressions expr, argument1, …, argumentn are evaluated is not specified.

Arguments and parameters are matched according to their respectivelabels. Argument order is irrelevant, except among arguments with thesame label, or no label.

If a parameter is specified as optional (label prefixed by ?) in thetype of expr, the corresponding argument will be automaticallywrapped with the constructor Some, except if the argument itself isalso prefixed by ?, in which case it is passed as is.If a non-labeled argument is passed, and its corresponding parameteris preceded by one or several optional parameters, then theseparameters are defaulted, i.e. the value None will bepassed for them.All other missing parameters (without corresponding argument), bothoptional and non-optional, will be kept, and the result of thefunction will still be a function of these missing parameters to thebody of f.

As a special case, if the function has a known arity, all thearguments are unlabeled, and their number matches the number ofnon-optional parameters, then labels are ignored and non-optionalparameters are matched in their definition order. Optional argumentsare defaulted.

In all cases but exact match of order and labels, without optionalparameters, the function type should be known at the applicationpoint. This can be ensured by adding a type constraint. Principalityof the derivation can be checked in the -principal mode.

Function definition

Two syntactic forms are provided to define functions. The first formis introduced by the keyword function:

functionpattern1->expr1
|
|patternn->exprn

This expression evaluates to a functional value with one argument.When this function is applied to a value v, this value ismatched against each pattern pattern1 to patternn.If one of these matchings succeeds, that is, if the value vmatches the pattern patterni for some i,then the expression expri associated to the selected patternis evaluated, and its value becomes the value of the functionapplication. The evaluation of expri takes place in anenvironment enriched by the bindings performed during the matching.

If several patterns match the argument v, the one that occursfirst in the function definition is selected. If none of the patternsmatches the argument, the exception Match_failure is raised.

The other form of function definition is introduced by the keyword fun:

funparameter1parametern-> expr

This expression is equivalent to:

funparameter1-> … fun parametern-> expr

An optional type constraint typexpr can be added before -> to enforcethe type of the result to be compatible with the constraint typexpr:

funparameter1parametern: typexpr-> expr

is equivalent to

funparameter1-> … fun parametern-> (expr: typexpr )

Beware of the small syntactic difference between a type constraint onthe last parameter

funparameter1 … (parametern: typexpr)-> expr

and one on the result

funparameter1parametern: typexpr-> expr

The parameter patterns ~lab and ~(lab [:typ])are shorthands for respectively ~lab: lab and~lab:( lab [:typ]), and similarly for their optionalcounterparts.

A function of the form fun?lab:( pattern= expr0)-> expr is equivalent to

fun?lab: ident->let pattern=match identwithSome ident-> ident|None-> expr0in expr

where identis a fresh variable, except that it is unspecified when expr0 is evaluated.

After these two transformations, expressions are of the form

fun [label1] pattern1-> … fun [labeln] patternn-> expr

If we ignore labels, which will only be meaningful at functionapplication, this is equivalent to

functionpattern1-> … function patternn-> expr

That is, the fun expression above evaluates to a curried functionwith n arguments: after applying this function n times to thevalues v1 … vn, the values will be matchedin parallel against the patterns pattern1patternn.If the matching succeeds, the function returns the value of expr inan environment enriched by the bindings performed during the matchings.If the matching fails, the exception Match_failure is raised.

Guards in pattern-matchings

The cases of a pattern matching (in the function, match andtry constructs) can include guard expressions, which arearbitrary boolean expressions that must evaluate to true for thematch case to be selected. Guards occur just before the -> token andare introduced by the when keyword:

functionpattern1 [when cond1]->expr1
|
|patternn [when condn]->exprn

Matching proceeds as described before, except that if the valuematches some pattern patterni which has a guard condi, then theexpression condi is evaluated (in an environment enriched by thebindings performed during matching). If condi evaluates to true,then expri is evaluated and its value returned as the result of thematching, as usual. But if condi evaluates to false, the matchingis resumed against the patterns following patterni.

Local definitions

The let and letrec constructs bind value names locally.The construct

letpattern1= expr1and … and patternn= exprnin expr

evaluates expr1exprn in some unspecified order and matchestheir values against the patterns pattern1patternn. If thematchings succeed, expr is evaluated in the environment enriched bythe bindings performed during matching, and the value of expr isreturned as the value of the whole let expression. If one of thematchings fails, the exception Match_failure is raised.

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

letident=fun parameter1parameterm-> expr

in a let expression, one may instead write

letident parameter1parameterm= expr

Recursive definitions of names are introduced by letrec:

letrecpattern1= expr1and … and patternn= exprnin expr

The only difference with the let construct described above isthat the bindings of names to values performed by thepattern-matching are considered already performed when the expressionsexpr1 to exprn are evaluated. That is, the expressions expr1to exprn can reference identifiers that are bound by one of thepatterns pattern1, …, patternn, and expect them to have thesame value as in expr, the body of the letrec construct.

The recursive definition is guaranteed to behave as described above ifthe expressions expr1 to exprn are function definitions(fun … or function …), and the patterns pattern1patternn are just value names, as in:

letrecname1=fun …and …and namen=fun …in expr

This defines name1 … namen as mutually recursive functionslocal to expr.

The behavior of other forms of letrec definitions isimplementation-dependent. The current implementation also supportsa certain class of recursive definitions of non-functional values,as explained in section 8.1.

Explicit polymorphic type annotations

(Introduced in OCaml 3.12)

Polymorphic type annotations in let-definitions behave in a waysimilar to polymorphic methods:

letpattern1: typ1typn. typeexpr= expr

These annotations explicitly require the defined value to be polymorphic,and allow one to use this polymorphism in recursive occurrences(when using letrec). Note however that this is a normal polymorphictype, unifiable with any instance of itself.

It is possible to define local exceptions in expressions: letexception constr-declin expr .The syntactic scope of the exception constructor is the innerexpression, but nothing prevents exception values created with thisconstructor from escaping this scope. Two executions of the definitionabove result in two incompatible exception constructors (as for anyexception definition). For instance, the following assertion istrue:

  1. let gen () = let exception A in A
  2. let () = assert(gen () <> gen ())

7.7.3 Control structures

Sequence

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

Conditional

The expression ifexpr1then expr2else expr3 evaluates tothe value of expr2 if expr1 evaluates to the boolean true,and to the value of expr3 if expr1 evaluates to the booleanfalse.

The elseexpr3 part can be omitted, in which case it defaults toelse().

Case expression

The expression

matchexpr
withpattern1->expr1
|
|patternn->exprn

matches the value of expr against the patterns pattern1 topatternn. If the matching against patterni succeeds, theassociated expression expri is evaluated, and its value becomes thevalue of the whole match expression. The evaluation ofexpri takes place in an environment enriched by the bindingsperformed during matching. If several patterns match the value ofexpr, the one that occurs first in the match expression isselected. If none of the patterns match the value of expr, theexception Match_failure is raised.

Boolean operators

The expression expr1&& expr2 evaluates to true if bothexpr1 and expr2 evaluate to true; otherwise, it evaluates tofalse. The first component, expr1, is evaluated first. Thesecond component, expr2, is not evaluated if the first componentevaluates to false. Hence, the expression expr1&& expr2 behavesexactly as

ifexpr1then expr2elsefalse.

The expression expr1|| expr2 evaluates to true if one ofthe expressionsexpr1 and expr2 evaluates to true; otherwise, it evaluates tofalse. The first component, expr1, is evaluated first. Thesecond component, expr2, is not evaluated if the first componentevaluates to true. Hence, the expression expr1|| expr2 behavesexactly as

ifexpr1thentrueelse expr2.

The boolean operators & and or are deprecated synonyms for(respectively) && and ||.

Loops

The expression whileexpr1do expr2done repeatedlyevaluates expr2 while expr1 evaluates to true. The loopcondition expr1 is evaluated and tested at the beginning of eachiteration. The whole while … done expression evaluates tothe unit value ().

The expression forname= expr1to expr2do expr3donefirst evaluates the expressions expr1 and expr2 (the boundaries)into integer values n and p. Then, the loop body expr3 isrepeatedly evaluated in an environment where name is successivelybound to the valuesn, n+1, …, p−1, p.The loop body is never evaluated if n > p.

The expression forname= expr1downto expr2do expr3doneevaluates similarly, except that name is successively bound to the valuesn, n−1, …, p+1, p.The loop body is never evaluated if n < p.

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

Exception handling

The expression

try expr
withpattern1->expr1
|
|patternn->exprn

evaluates the expression expr and returns its value if theevaluation of expr does not raise any exception. If the evaluationof expr raises an exception, the exception value is matched againstthe patterns pattern1 to patternn. If the matching againstpatterni succeeds, the associated expression expri is evaluated,and its value becomes the value of the whole try expression. Theevaluation of expri takes place in an environment enriched by thebindings performed during matching. If several patterns match the value ofexpr, the one that occurs first in the try expression isselected. If none of the patterns matches the value of expr, theexception value is raised again, thereby transparently “passingthrough” the try construct.

7.7.4 Operations on data structures

Products

The expression expr1, … , exprn evaluates to then-tuple of the values of expressions expr1 to exprn. Theevaluation order of the subexpressions is not specified.

Variants

The expression constr expr evaluates to the unary variant valuewhose constructor is constr, and whose argument is the value ofexpr. Similarly, the expression constr( expr1, … , exprn) evaluates to the n-ary variant value whose constructor isconstr and whose arguments are the values of expr1, …, exprn.

The expression constr( expr1, …, exprn) evaluates to thevariant value whose constructor is constr, and whose arguments arethe values of expr1exprn.

For lists, some syntactic sugar is provided. The expressionexpr1:: expr2 stands for the constructor (::) applied to the arguments (expr1, expr2), and thereforeevaluates to the list whose head is the value of expr1 and whose tailis the value of expr2. The expression [expr1; … ; exprn] is equivalent to expr1:: … :: exprn::[], and therefore evaluates to the list whose elements are thevalues of expr1 to exprn.

Polymorphic variants

The expression `tag-name expr evaluates to the polymorphic variantvalue whose tag is tag-name, and whose argument is the value of expr.

Records

The expression {field1 [=expr1] ; … ; fieldn [=exprn]} evaluates to the record value{ field1 = v1; …; fieldn = vn }where vi is the value of expri for i = 1,… , n.A single identifier fieldk stands for fieldk= fieldk,and a qualified identifier module-path. fieldk stands formodule-path. fieldk= fieldk.The fields field1 to fieldn must all belong to the same recordtype; each field of this record type must appear exactlyonce in the record expression, though they can appear in anyorder. The order in which expr1 to exprn are evaluated is notspecified. Optional type constraints can be added after each field{field1: typexpr1= expr1;… ; fieldn: typexprn= exprn}to force the type of fieldk to be compatible with typexprk.

The expression{exprwith field1 [=expr1] ; … ; fieldn [=exprn] }builds a fresh record with fields field1fieldn equal toexpr1exprn, and all other fields having the same value asin the record expr. In other terms, it returns a shallow copy ofthe record expr, except for the fields field1fieldn,which are initialized to expr1exprn. As previously,single identifier fieldk stands for fieldk= fieldk,a qualified identifier module-path. fieldk stands formodule-path. fieldk= fieldk and it ispossible to add an optional type constraint on each field being updatedwith{exprwith field1: typexpr1= expr1; … ; fieldn: typexprn= exprn}.

The expression expr1. field evaluates expr1 to a recordvalue, and returns the value associated to field in this recordvalue.

The expression expr1. field<- expr2 evaluates expr1 to a recordvalue, which is then modified in-place by replacing the valueassociated to field in this record by the value ofexpr2. This operation is permitted only if field has beendeclared mutable in the definition of the record type. The wholeexpression expr1. field<- expr2 evaluates to the unit value().

Arrays

The expression [|expr1; … ; exprn|] evaluates toa n-element array, whose elements are initialized with the values ofexpr1 to exprn respectively. The order in which theseexpressions are evaluated is unspecified.

The expression expr1.( expr2) returns the value of elementnumber expr2 in the array denoted by expr1. The first elementhas number 0; the last element has number n−1, where n is thesize of the array. The exception Invalid_argument is raised if theaccess is out of bounds.

The expression expr1.( expr2)<- expr3 modifies in-placethe array denoted by expr1, replacing element number expr2 bythe value of expr3. The exception Invalid_argument is raised ifthe access is out of bounds. The value of the whole expression is ().

Strings

The expression expr1.[ expr2] returns the value of characternumber expr2 in the string denoted by expr1. The first characterhas number 0; the last character has number n−1, where n is thelength of the string. The exception Invalid_argument is raised if theaccess is out of bounds.

The expression expr1.[ expr2]<- expr3 modifies in-placethe string denoted by expr1, replacing character number expr2 bythe value of expr3. The exception Invalid_argument is raised ifthe access is out of bounds. The value of the whole expression is ().

Note: this possibility is offered only for backwardcompatibility with older versions of OCaml and will be removed in afuture version. New code should use byte sequences and the Bytes.setfunction.

7.7.5 Operators

Symbols from the class infix-symbol, as well as the keywords*, +, -, -., =, !=, <, >, or, ||,&, &&, :=, mod, land, lor, lxor, lsl, lsr,and asr can appear in infix position (between twoexpressions). Symbols from the class prefix-symbol, as well asthe keywords - and -.can appear in prefix position (in front of an expression).

Infix and prefix symbols do not have a fixed meaning: they are simplyinterpreted as applications of functions bound to the namescorresponding to the symbols. The expression prefix-symbol expr isinterpreted as the application (prefix-symbol) expr. Similarly, the expression expr1 infix-symbol expr2 isinterpreted as the application (infix-symbol) expr1 expr2.

The table below lists the symbols defined in the initial environmentand their initial meaning. (See the description of the corelibrary module Pervasives in chapter 23 for moredetails). Their meaning may be changed at any time usinglet(infix-op) name1 name2= …

Note: the operators &&, ||, and ~- are handled speciallyand it is not advisable to change their meaning.

The keywords - and -. can appear both as infix andprefix operators. When they appear as prefix operators, they areinterpreted respectively as the functions (~-) and (~-.).

OperatorInitial meaning
+Integer addition.
- (infix)Integer subtraction.
~- - (prefix)Integer negation.
Integer multiplication.
/Integer division.Raise Division_by_zero if second argument is zero.
modInteger modulus. RaiseDivision_by_zero if second argument is zero.
landBitwise logical “and” on integers.
lorBitwise logical “or” on integers.
lxorBitwise logical “exclusive or” on integers.
lslBitwise logical shift left on integers.
lsrBitwise logical shift right on integers.
asrBitwise arithmetic shift right on integers.
+.Floating-point addition.
-. (infix)Floating-point subtraction.
~-. -. (prefix)Floating-point negation.
.Floating-point multiplication.
/.Floating-point division.
**Floating-point exponentiation.
@List concatenation.
^String concatenation.
!Dereferencing (return the currentcontents of a reference).
:=Reference assignment (update thereference given as first argument with the value of the secondargument).
=Structural equality test.
<>Structural inequality test.
==Physical equality test.
!=Physical inequality test.
<Test “less than”.
<=Test “less than or equal”.
>Test “greater than”.
>=Test “greater than or equal”.
&& &Boolean conjunction.
|| orBoolean disjunction.

7.7.6 Objects

Object creation

When class-path evaluates to a class body, newclass-pathevaluates to a new object containing the instance variables andmethods of this class.

When class-path evaluates to a class function, newclass-pathevaluates to a function expecting the same number of arguments andreturning a new object of this class.

Immediate object creation

Creating directly an object through the objectclass-bodyendconstruct is operationally equivalent to defining locally a classclass-name=object class-bodyend —see sections7.9.2 and following for the syntax of class-body—and immediately creating a single object from it by newclass-name.

The typing of immediate objects is slightly different from explicitlydefining a class in two respects. First, the inferred object type maycontain free type variables. Second, since the class body of animmediate object will never be extended, its self type can be unifiedwith a closed object type.

Method invocation

The expression expr# method-name invokes the methodmethod-name of the object denoted by expr.

If method-name is a polymorphic method, its type should be known atthe invocation site. This is true for instance if expr is the nameof a fresh object (letident = new class-path … ) or ifthere is a type constraint. Principality of the derivation can bechecked in the -principal mode.

Accessing and modifying instance variables

The instance variables of a class are visible only in the body of themethods defined in the same class or a class that inherits from theclass defining the instance variables. The expression inst-var-nameevaluates to the value of the given instance variable. The expressioninst-var-name<- expr assigns the value of expr to the instancevariable inst-var-name, which must be mutable. The whole expressioninst-var-name<- expr evaluates to ().

Object duplication

An object can be duplicated using the library function Oo.copy(seeModule Oo). Inside a method, the expression {< [inst-var-name [=expr] { ;inst-var-name [=expr] }] >}returns a copy of self with the given instance variables replaced bythe values of the associated expressions. A single instance variablename id stands for id= id. Other instance variables have the samevalue in the returned object as in self.

7.7.7 Coercions

Expressions whose type contains object or polymorphic variant typescan be explicitly coerced (weakened) to a supertype.The expression (expr:> typexpr) coerces the expression exprto type typexpr.The expression (expr: typexpr1:> typexpr2) coerces theexpression expr from type typexpr1 to type typexpr2.

The former operator will sometimes fail to coerce an expression exprfrom a type typ1 to a type typ2even if type typ1 is a subtype of typetyp2: in the current implementation it only expands two levels oftype abbreviations containing objects and/or polymorphic variants,keeping only recursion when it is explicit in the class type (for objects).As an exception to the above algorithm, if both the inferred type of exprand typ are ground (i.e. do not contain type variables), theformer operator behaves as the latter one, taking the inferred type ofexpr as typ1. In case of failure with the former operator,the latter one should be used.

It is only possible to coerce an expression expr from typetyp1 to type typ2, if the type of expr is an instance oftyp1 (like for a type annotation), and typ1 is a subtypeof typ2. The type of the coerced expression is aninstance of typ2. If the types contain variables,they may be instantiated by the subtyping algorithm, but this is onlydone after determining whether typ1 is a potential subtype oftyp2. This means that typing may fail during this latterunification step, even if some instance of typ1 is a subtype ofsome instance of typ2.In the following paragraphs we describe the subtyping relation used.

Object types

A fixed object type admits as subtype any object type that includes allits methods. The types of the methods shall be subtypes of those inthe supertype. Namely,

<met1: typ1; … ; metn: typn>

is a supertype of

<met1: typ1; … ;metn: typn;metn+1:typn+1; … ;metn+m:typn+m [;..] >

which may contain an ellipsis .. if every typi is a supertype ofthe corresponding typi.

A monomorphic method type can be a supertype of a polymorphic methodtype. Namely, if typ is an instance of typ′, then 'a1… 'an.typ′ is a subtype of typ.

Inside a class definition, newly defined types are not available forsubtyping, as the type abbreviations are not yet completelydefined. There is an exception for coercing self to the (exact)type of its class: this is allowed if the type of self does notappear in a contravariant position in the class type, i.e. ifthere are no binary methods.

Polymorphic variant types

A polymorphic variant type typ is a subtype of another polymorphicvariant type typ′ if the upper bound of typ (i.e. themaximum set of constructors that may appear in an instance of typ)is included in the lower bound of typ′, and the types of argumentsfor the constructors of typ are subtypes of those intyp′. Namely,

[[<] [C]($49815e5ab82eadea.md#constr-name)<sub>1</sub>of [typ]($2ecc3987e27872fa.md#typexpr)<sub>1</sub>| … | Cnof typn]

which may be a shrinkable type, is a subtype of

[[>] [C]($49815e5ab82eadea.md#constr-name)<sub>1</sub>of [typ]($2ecc3987e27872fa.md#typexpr)′<sub>1</sub>| … |Cnof typn|[C]($49815e5ab82eadea.md#constr-name)<sub>n+1</sub>of[typ]($2ecc3987e27872fa.md#typexpr)′<sub>n+1</sub>| … |Cn+moftypn+m]

which may be an extensible type, if every typi is a subtype of typi.

Variance

Other types do not introduce new subtyping, but they may propagate thesubtyping of their arguments. For instance, typ1 typ2 is asubtype of typ1typ2 when typ1 and typ2 arerespectively subtypes of typ1 and typ2.For function types, the relation is more subtle:typ1-> typ2 is a subtype of typ1 ->typ2if typ1 is a supertype of typ1 and typ2 is asubtype of typ2. For this reason, function types are covariant intheir second argument (like tuples), but contravariant in their firstargument. Mutable types, like array or ref are neither covariantnor contravariant, they are nonvariant, that is they do not propagatesubtyping.

For user-defined types, the variance is automatically inferred: aparameter is covariant if it has only covariant occurrences,contravariant if it has only contravariant occurrences,variance-free if it has no occurrences, and nonvariant otherwise.A variance-free parameter may change freely through subtyping, it doesnot have to be a subtype or a supertype.For abstract and private types, the variance must be given explicitly(see section 7.8.1),otherwise the default is nonvariant. This is also the case forconstrained arguments in type definitions.

7.7.8 Other

Assertion checking

OCaml supports the assert construct to check debugging assertions.The expression assertexpr evaluates the expression expr andreturns () if expr evaluates to true. If it evaluates tofalse the exceptionAssert_failure is raised with the source file name and thelocation of expr as arguments. Assertionchecking can be turned off with the -noassert compiler option. Inthis case, expr is not evaluated at all.

As a special case, assert false is reduced toraise(Assert_failure …), which gives it a polymorphictype. This means that it can be used in place of any expression (forexample as a branch of any pattern-matching). It also means thatthe assert false “assertions” cannot be turned off by the-noassert option.

Lazy expressions

The expression lazyexpr returns a value v of type Lazy.t thatencapsulates the computation of expr. The argument expr is notevaluated at this point in the program. Instead, its evaluation willbe performed the first time the function Lazy.force is applied to the valuev, returning the actual value of expr. Subsequent applicationsof Lazy.force to v do not evaluate expr again. Applicationsof Lazy.force may be implicit through pattern matching (see 7.6).

Local modules

The expressionletmodulemodule-name= module-exprin exprlocally binds the module expression module-expr to the identifiermodule-name during the evaluation of the expression expr.It then returns the value of expr. For example:

  1. let remove_duplicates comparison_fun string_list =
  2. let module StringSet =
  3. Set.Make(struct type t = string
  4. let compare = comparison_fun end) in
  5. StringSet.elements
  6. (List.fold_right StringSet.add string_list StringSet.empty)
  7. val remove_duplicates :
  8. (string -> string -> int) -> string list -> string list = <fun>

Local opens

The expressions letopenmodule-pathin expr andmodule-path.( expr) are strictly equivalent. Theseconstructions locally open the module referred to by the module pathmodule-path in the respective scope of the expression expr.

When the body of a local open expression is delimited by[], [||], or {}, the parentheses can be omitted.For expression, parentheses can also be omitted for {<>}.For example, module-path.[ expr] is equivalent tomodule-path.([ expr]), and module-path.[| expr|] isequivalent to module-path.([| expr|]).