open File in (*Here, File is opened*) lines_of "some_file" (*Here, File is not opened anymore*)These modules do not need to be named. For instance, you may write
open Hashtbl.Make(String) in (*...*)
open Random with self_init ()This extract is equivalent to
open Random let _ = self_init ()This feature is provided as it may sometimes increase readability.
open List, ArrayThis extract is equivalent to
open List open ArrayThis feature is provided as it may sometimes increase readability.
module E = Enum with Labels, LExceptionlessThis extract defines a local module name
Ewith all the values and types of modules
LExceptionless. In particular, some values defined in
Enummay be overridden with values defined in
module Enum = struct include Enum include Labels include LExceptionless endThis feature is provided as it may sometimes increase readability.
IO, which defines operations for input and output: this module contains a submodule
BigEndian, which defines operations which should be used to communicate with specific architectures. One of these functions is
IO.read_floatis adapted to small-endian architectures, while
IO.BigEndian.read_floatis adapted to big-endian architectures The functions of
BigEndianhave the same name as functions of
IO. The following extract will therefore open both
BigEndianin one operation:
open IO, BigEndianThis extract is equivalent to
open IO open BigEndian
let...in.... This extension adds a dual construction
... where ..., once again, to increase readability when appropriate.
let...in...lets you define a value and use it immediately,
... where...lets you use a value and define it immediately, as is often done in mathematic notations. Consider
let fibo n = fst fibo_aux n where rec fibo_aux = function | 0 -> (1, 1) | 1 -> (1, 2) | n -> (a, a + b) where let (a, b) = fibo_aux ( n - 1 )This extract is equivalent to
let fibo n = let rec fibo_aux = function | 0 -> (1, 1) | 1 -> (1, 2) | n -> let (a, b) = fibo_aux (n - 1) in (a, (a + b)) in fst (fibo_aux n)More generally,
<expression> where <definitions>is equivalent to
let <definitions> in <expression>. Note that you can define (mutually) recursive functions with
wherejust as well as with
where letinstead of
a where b where cis equivalent to
(a where b) where c
let a = b where c and dis equivalent to
let a = (b where c and d)
The global form is
[? output | comp_item ; comp_item ; ... ].
output is an expression and a comp_item is either a guard (a boolean expression), or a generator of the form
pattern <- expression.
Variables bound in the pattern can be used in the following
comprehension items, and in the output expression.
let pythagorean_triples n = [? (a,b,c) | a <- 1--n; b <- a--n; c <- b--n; a*a + b*b = c*c ]
By default, the output in an enumeration, and generator expressions
are assumed to be enumerations. It is possible to choose a different
data structure with the
module : expression syntax.
let positive_array_of_enum e = [? Array : n | n <- e; n > 0 ] let combine la lb = [? List : (a, b) | a <- List : la; b <- List : lb ]
Comprehension expressions rely on the presence in the given module of
the following operations (where
'a t represents the
data-structure type :
val filter : ('a -> bool) -> 'a t -> 'a t val concat : 'a t t -> 'a t val map : ('a -> 'b) -> 'a t -> 'b t val filter_map : ('a -> 'b option) -> 'a t -> 'b t (* used for refutable patterns in generators *) val enum : 'a t -> 'a Enum.t val of_enum : 'a Enum.t -> 'a t
If your module does not provide the first four operations but only
the enum conversion functions, you could still benefit from the
comprehension syntax by using eg.
foo <- Mod.enum bar instead
foo <- Mod : bar.
Declaring a Rope is as simple as
let foo = r"Some Unicode text (Latin-1 encoded)" let bar = ur"Some Unicode text (UTF-8 encoded)"
This defines a new value
foo, with type
Rope.t, the type of (immutable) Unicode ropes.
Of course, this manipulation doesn't have to happen at the highest-level:
let append_string_to_rope x = Rope.append x (r"Some more Unicode text")
Note that ropes, being immutable, are automatically optimized, i.e. this is equivalent to
let some_unique_name = Rope.of_latin1 "Some more Unicode text" let append_string_to_rope x = Rope.append x some_unique_nameIt is possible to use the same syntax to define
u"Some UTF-8 string", with type
ro"Some read-only string", with type
rw"Some read-write string", with type
[`Read | `Write] String.Cap.t
wo"Some write-only string", with type
with sexpis added to type definitions. This construction may be used to automatically (or semi-automatically, if need arises) generate functions to transform values into S-Expressions.
TYPE_CONV_PATH "Current.Module.Name" (*Required*) type color = Spade | Heart | Club | Diamond with sexp type value = Number of int | Ace | King | Queen | Jack with sexp type card = color * value with sexpThis extract defines types
card, as well as functions:
val sexp_of_color: color -> SExpr.t val color_of_sexp: SExpr.t -> color val sexp_of_value: value -> SExpr.t val value_of_sexp: SExpr.t -> value val sexp_of_card : card -> SExpr.t val card_of_sexp : SExpr.t -> card
with sexp. If you encounter a type which is not compatible with this boilerplate generator, you may define manually functions
foo_of_sexp. These functions will integrate nicely with the rest of S-Expressions.
where, defined by pa_where
[? .. | .. ](and
[ .. | .. ]), defined by