mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-06 03:05:28 -05:00
175 lines
5.2 KiB
Text
175 lines
5.2 KiB
Text
= Tutorial
|
|
:source-highlighter: pygments
|
|
|
|
This tutorial contains a few examples to illustrate the features and
|
|
usage of containers. We assume containers is installed and that
|
|
the library is loaded, e.g. with:
|
|
|
|
[source,OCaml]
|
|
----
|
|
#require "containers";;
|
|
----
|
|
|
|
We will start with a few list helpers, then look at other parts of
|
|
the library, including printers, maps, etc.
|
|
|
|
[source,OCaml]
|
|
----
|
|
|
|
(* quick reminder of this awesome standard operator *)
|
|
# (|>) ;;
|
|
- : 'a -> ('a -> 'b) -> 'b = <fun>
|
|
|
|
# open CCList.Infix;;
|
|
|
|
# let l = 1 -- 100;;
|
|
val l : int list = [1; 2; .....]
|
|
|
|
# l
|
|
|> CCList.filter_map
|
|
(fun x-> if x mod 3=0 then Some (float x) else None)
|
|
|> CCList.take 5 ;;
|
|
- : float list = [3.; 6.; 9.; 12.; 15.]
|
|
|
|
# let l2 = l |> CCList.take_while (fun x -> x<10) ;;
|
|
val l2 : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9]
|
|
|
|
(* an extension of Map.Make, compatible with Map.Make(CCInt) *)
|
|
# module IntMap = CCMap.Make(CCInt);;
|
|
|
|
(* conversions using the "sequence" type, fast iterators that are
|
|
pervasively used in containers. Combinators can be found
|
|
in the opam library "sequence". *)
|
|
# let map =
|
|
l2
|
|
|> List.map (fun x -> x, string_of_int x)
|
|
|> CCList.to_seq
|
|
|> IntMap.of_seq;;
|
|
val map : string CCIntMap.t = <abstr>
|
|
|
|
(* check the type *)
|
|
# CCList.to_seq ;;
|
|
- : 'a list -> 'a sequence = <fun>
|
|
# IntMap.of_seq ;;
|
|
- : (int * 'a) CCMap.sequence -> 'a IntMap.t = <fun>
|
|
|
|
(* we can print, too *)
|
|
# Format.printf "@[<2>map =@ @[<hov>%a@]@]@."
|
|
(IntMap.print CCFormat.int CCFormat.string_quoted)
|
|
map;;
|
|
map =
|
|
[1 --> "1", 2 --> "2", 3 --> "3", 4 --> "4", 5 --> "5", 6 --> "6",
|
|
7 --> "7", 8 --> "8", 9 --> "9"]
|
|
- : unit = ()
|
|
|
|
(* options are good *)
|
|
# IntMap.get 3 map |> CCOpt.map (fun s->s ^ s);;
|
|
- : string option = Some "33"
|
|
|
|
----
|
|
|
|
== New types: `CCVector`, `CCHeap`, `CCError`, `CCResult`
|
|
|
|
Containers also contains (!) a few datatypes that are not from the standard
|
|
library but that are useful in a lot of situations:
|
|
|
|
CCVector::
|
|
A resizable array, with a mutability parameter. A value of type
|
|
`('a, CCVector.ro) CCVector.t` is an immutable vector of values of type `'a`,
|
|
whereas a `('a, CCVector.rw) CCVector.t` is a mutable vector that
|
|
can be modified. This way, vectors can be used in a quite functional
|
|
way, using operations such as `map` or `flat_map`, or in a more
|
|
imperative way.
|
|
CCHeap::
|
|
A priority queue (currently, leftist heaps) functorized over
|
|
a module `sig val t val leq : t -> t -> bool` that provides a type `t`
|
|
and a partial order `leq` on `t`.
|
|
CCError::
|
|
An error type for making error handling more explicit (an error monad,
|
|
really, if you're not afraid of the "M"-word). It is similar to the
|
|
more recent `CCResult`, but works with polymorphic variants for
|
|
compatibility with the numerous libraries that use the same type,
|
|
that is, `type ('a, 'b) CCError.t = [`Ok of 'a | `Error of 'b]`.
|
|
CCResult::
|
|
It uses the new `result` type from the standard library (or from
|
|
the retrocompatibility package on opam), and presents an interface
|
|
similar to `CCError`. In an indeterminate amount of time, it will
|
|
totally replace `CCError`.
|
|
|
|
Now for a few examples:
|
|
|
|
[source,OCaml]
|
|
----
|
|
|
|
(* create a new empty vector. It is mutable, for otherwise it would
|
|
not be very useful. *)
|
|
# CCVector.create;;
|
|
- : unit -> ('a, CCVector.rw) CCVector.t = <fun>
|
|
|
|
(* init, similar to Array.init, can be used to produce a
|
|
vector that is mutable OR immutable (see the 'mut parameter?) *)
|
|
# CCVector.init ;;
|
|
- : int -> (int -> 'a) -> ('a, 'mut) CCVector.t = <fun>c
|
|
|
|
(* use the infix (--) operator for creating a range. Notice
|
|
that v is a vector of integer but its mutability is not
|
|
decided yet. *)
|
|
# let v = CCVector.(1 -- 10);;
|
|
val v : (int, '_a) CCVector.t = <abstr>
|
|
|
|
# Format.printf "v = @[%a@]@." (CCVector.print CCInt.print) v;;
|
|
v = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
|
|
|
(* now let's mutate v *)
|
|
# CCVector.push v 42;;
|
|
- : unit = ()
|
|
|
|
(* now v is a mutable vector *)
|
|
# v;;
|
|
- : (int, CCVector.rw) CCVector.t = <abstr>
|
|
|
|
(* functional combinators! *)
|
|
# let v2 = v
|
|
|> CCVector.map (fun x-> x+1)
|
|
|> CCVector.filter (fun x-> x mod 2=0)
|
|
|> CCVector.rev ;;
|
|
val v2 : (int, '_a) CCVector.t = <abstr>
|
|
|
|
# Format.printf "v2 = @[%a@]@." (CCVector.print CCInt.print) v2;;
|
|
v2 = [10, 8, 6, 4, 2]
|
|
|
|
(* let's transfer to a heap *)
|
|
# module IntHeap = CCHeap.Make(struct type t = int let leq = (<=) end);;
|
|
|
|
# let h = v2 |> CCVector.to_seq |> IntHeap.of_seq ;;
|
|
val h : IntHeap.t = <abstr>
|
|
|
|
(* We can print the content of h
|
|
(printing is not necessarily in order, though) *)
|
|
# Format.printf "h = [@[%a@]]@." (IntHeap.print CCInt.print) h;;
|
|
h = [2,4,6,8,10]
|
|
|
|
(* we can remove the first element, which also returns a new heap
|
|
that does not contain it — CCHeap is a functional data structure *)
|
|
# IntHeap.take h;;
|
|
- : (IntHeap.t * int) option = Some (<abstr>, 2)
|
|
|
|
# let h', x = IntHeap.take_exn h ;;
|
|
val h' : IntHeap.t = <abstr>
|
|
val x : int = 2
|
|
|
|
(* see, 2 is removed *)
|
|
# IntHeap.to_list h' ;;
|
|
- : int list = [4; 6; 8; 10]
|
|
|
|
----
|
|
|
|
=== To go further: containers.data
|
|
|
|
There is also a sub-library called `containers.data`, with lots of
|
|
more specialized data-structures.
|
|
The documentation contains the API for all the modules
|
|
(see link:README.adoc[the readme]); they also provide
|
|
interface to `sequence` and, as the rest of containers, minimize
|
|
dependencies over other modules.
|
|
|