This chapter describes language extensions and convenience features
that are implemented in Objective Caml, but not described in the
Objective Caml reference manual.
7.1 |
Integer literals for types int32, int64 and nativeint |
|
int32-literal |
::= |
integer-literal l |
int64-literal |
::= |
integer-literal L |
nativeint-literal |
::= |
integer-literal n |
An integer literal can be followed by one of the letters l, L or n
to indicate that this integer has type int32, int64 or nativeint
respectively, instead of the default type int for integer literals.
The library modules Int32[Int32],
Int64[Int64] and Nativeint[Nativeint]
provide operations on these integer types.
7.2 |
Streams and stream parsers |
|
Streams and stream parsers are no longer part of the Objective Caml
language, but available through a Camlp4 syntax extension. See the
Camlp4 reference manual for more information. Objective Caml programs
that use streams and stream parsers can be compiled with the
-pp camlp4o option to ocamlc and ocamlopt. For interactive use,
run ocaml and issue the #load "camlp4o.cma";;
command.
7.3 |
Recursive definitions of values |
|
As mentioned in section 6.7.1, the let rec binding
construct, in addition to the definition of recursive functions,
also supports a certain class of recursive definitions of
non-functional values, such as
let rec name1 = 1 :: name2
and name2 = 2 :: name1
in expr
which binds name1 to the cyclic list 1::2::1::2::..., and
name2 to the cyclic list 2::1::2::1::...Informally, the class of accepted definitions consists of those
definitions where the defined names occur only inside function
bodies or as argument to a data constructor.
More precisely, consider the expression:
let rec name1 = expr1 and ... and namen = exprn in expr
It will be accepted if each one of expr1 ... exprn is
statically constructive with respect to name1 ... namen and
not immediately linked to any of name1 ... namen
An expression e is said to be statically constructive
with respect to the variables name1 ... namen if at least
one of the following conditions is true:
-
e has no free occurrence of any of name1 ... namen
- e is a variable
- e has the form fun ... -> ...
- e has the form function ... -> ...
- e has the form lazy ( ... )
- e has one of the following forms, where each one of
expr1 ... exprm is statically constructive with respect to
name1 ... namen, and expr0 is statically constructive with
respect to name1 ... namen, xname1 ... xnamem:
-
let [rec] xname1 = expr1 and ...
and xnamem = exprm in expr0
- let module ... in expr1
- constr ( expr1, ... , exprm)
- `tag-name ( expr1, ... , exprm)
- [| expr1; ... ; exprm |]
- { field1 = expr1; ... ; fieldm = exprm }
- { expr1 with field2 = expr2; ... ;
fieldm = exprm } where expr1 is not immediately
linked to name1 ... namen
- ( expr1, ... , exprm )
- expr1; ... ; exprm
An expression e is said to be immediately linked to the variable
name in the following cases:
-
e is name
- e has the form expr1; ... ; exprm where exprm
is immediately linked to name
- e has the form let [rec] xname1 = expr1 and ...
and xnamem = exprm in expr0 where expr0 is immediately
linked to name or to one of the xnamei such that expri
is immediately linked to name.
In patterns, Objective Caml recognizes the form
' c ' .. ' d '
(two character literals separated by ..) as shorthand for the pattern
' c ' | ' c1 ' | ' c2 ' | ...
| ' cn ' | ' d '
where c1, c2, ..., cn are the characters
that occur between c and d in the ASCII character set. For
instance, the pattern '0'..'9' matches all characters that are digits.
Objective Caml supports the assert construct to check debugging assertions.
The expression assert expr evaluates the expression expr and
returns () if expr evaluates to true. Otherwise, the exception
Assert_failure is raised with the source file name and the
location of expr as arguments. Assertion
checking can be turned off with the -noassert compiler option.
As a special case, assert false is reduced to
raise (Assert_failure ...), which is polymorphic (and
is not turned off by the -noassert option).
The expression lazy expr returns a value v of type Lazy.t that
encapsulates the computation of expr. The argument expr is not
evaluated at this point in the program. Instead, its evaluation will
be performed the first time Lazy.force is applied to the value
v, returning the actual value of expr. Subsequent applications
of Lazy.force to v do not evaluate expr again.
For more information, see the description of module Lazy in the
standard library (see
Module Lazy).
The expression
let module module-name = module-expr in expr
locally binds the module expression module-expr to the identifier
module-name during the evaluation of the expression expr.
It then returns the value of expr. For example:
let remove_duplicates comparison_fun string_list =
let module StringSet =
Set.Make(struct type t = string
let compare = comparison_fun end) in
StringSet.elements
(List.fold_right StringSet.add string_list StringSet.empty)
type-representation |
::= |
... |
|
| |
= private constr-decl { | constr-decl } |
|
| |
= private { field-decl { ; field-decl } } |
Private types are variant or record types. Values of
these types can be de-structured normally in pattern-matching or via
the expr . field notation for record accesses. However, values of
these types cannot be constructed directly by constructor application
or record construction. Moreover, assignment on a mutable field of a
private record type is not allowed.
The typical use of private types is in the export signature of a
module, to ensure that construction of values of the private type always
go through the functions provided by the module, while still allowing
pattern-matching outside the defining module. For example:
module M : sig
type t = private A | B of int
val a : t
val b : int -> t
end
= struct
type t = A | B of int
let a = A
let b n = assert (n > 0); B n
end
Here, the private declaration ensures that in any value of type
M.t, the argument to the B constructor is always a positive integer.
definition |
::= |
... |
|
| |
module rec module-name : module-type = module-expr
{ and module-name: module-type = module-expr } |
specification |
::= |
... |
|
| |
module rec module-name : module-type
{ and module-name: module-type } |
Recursive module definitions, introduced by the 'module rec' ...'and' ... construction, generalize regular module definitions
module module-name = module-expr and module specifications
module module-name : module-type by allowing the defining
module-expr and the module-type to refer recursively to the module
identifiers being defined. A typical example of a recursive module
definition is:
module rec A : sig
type t = Leaf of string | Node of ASet.t
val compare: t -> t -> int
end
= struct
type t = Leaf of string | Node of ASet.t
let compare t1 t2 =
match (t1, t2) with
(Leaf s1, Leaf s2) -> Pervasives.compare s1 s2
| (Leaf _, Node _) -> 1
| (Node _, Leaf _) -> -1
| (Node n1, Node n2) -> ASet.compare n1 n2
end
and ASet : Set.S with type elt = A.t
= Set.Make(A)
It can be given the following specification:
module rec A : sig
type t = Leaf of string | Node of ASet.t
val compare: t -> t -> int
end
and ASet : Set.S with type elt = A.t
This is an experimental extension of Objective Caml: the class of
recursive definitions accepted, as well as its dynamic semantics are
not final and subject to change in future releases.
Currently, the compiler requires that all dependency cycles between
the recursively-defined module identifiers go through at least one
``safe'' module. A module is ``safe'' if all value definitions that
it contains have function types ty1 -> ty2. Evaluation of a
recursive module definition proceeds by building initial values for
the safe modules involved, binding all (functional) values to
fun x -> raise Undefined_recursive_module. The defining
module expressions are then evaluated, and the initial values
for the safe modules are replaced by the values thus computed. If a
function component of a safe module is applied during this computation
(which corresponds to an ill-founded recursive definition), the
Undefined_recursive_module exception is raised.