batteries.pa_openin.syntax
)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 include ExceptionLess, LabelsThis extract defines a local module name
E
with all the values and types of modules Enum
,
ExceptionLess
and Labels
. In
particular, some values defined in Enum
may be overridden with values defined in ExceptionLess
and/or Labels
.
module Enum = struct include Enum include ExceptionLess include Labels 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 read_float
: IO.read_float
is
adapted to small-endian architectures, while IO.BigEndian.read_float
is adapted to big-endian architectures
The
functions of BigEndian
have the same name as functions
of IO
. The following extract will therefore open
both IO
and BigEndian
in one operation:
open IO, BigEndianThis extract is equivalent to
open IO open BigEndian
batteries.pa_where.syntax
)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 where
just as well as with let
.
where let
instead of where
.
a where b where c
is equivalent to (a where b) where c
let a = b where c and d
is equivalent to let a = (b where c and d)
batteries.pa_comprehension.syntax
)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 : 'a array
, 'a
Enum.t
...) :
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
of foo <- Mod : bar
.
batteries.pa_string.syntax
)Declaring a Rope is as simple as
let foo = r"Some Unicode text"
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 UTF8.t
ro"Some read-only string"
, with type [`Read] String.Cap.t
rw"Some read-write string"
, with type [`Read | `Write] String.Cap.t
wo"Some write-only string"
, with type [`Write] String.Cap.t
sexplib.syntax
)with sexp
is 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
color
, value
and 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
sexp_of_foo
and foo_of_sexp
. These functions
will integrate nicely with the rest of S-Expressions.
where
, defined by pa_where