File: containers.md

package info (click to toggle)
ocaml-containers 3.15%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 2,412 kB
  • sloc: ml: 33,221; sh: 122; makefile: 32
file content (81 lines) | stat: -rw-r--r-- 2,376 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# More about OCaml-containers

This document contains more information on some modules of Containers.

```ocaml
# #require "containers";;
```

## Hash combinators: `CCHash`

Although OCaml provides polymorphic hash tables (`('a,'b) Hashtbl.t`)
using the polymorphic equality `(=)` and hash `Hashtbl.hash`, it is often
safer and more efficient to use `Hashtbl.Make` (or the extended `CCHashtbl.Make`)
with custom equality and hash functions.

`CCHash` provides combinators for writing hash functions:

```ocaml
# module H = CCHash;;
module H = CCHash

# let hash1 : (int * bool) list H.t = H.(list (pair int bool));;
val hash1 : (int * bool) list H.t = <fun>
```

```ocaml non-deterministic=output
# hash1 [1, true; 2, false; 3, true];;
- : int = 636041136
# hash1 CCList.(1 -- 1000 |> map (fun i->i, i mod 2 = 0));;
- : int = 845685523
# hash1 CCList.(1 -- 1001 |> map (fun i->i, i mod 2 = 0));;
- : int = 381026697
```

The polymorphic hash function is still present, as `CCHash.poly`.
The functions `CCHash.list_comm` and `CCHash.array_comm` allow to hash
lists and arrays while ignoring the order of elements: all permutations
of the input will have the same hash.

## Parser Combinator: `CCParse`

The module `CCParse` defines basic parser combinators on strings.
Adapting [angstrom's tutorial example](https://github.com/inhabitedtype/angstrom#usage)
gives the following snippet.
Note that backtracking is explicit in `CCParse`, hence
the use of `try_` to allow it in some places.
Explicit memoization with `memo` and `fix_memo` is also possible.

```ocaml
open CCParse.Infix
module P = CCParse

let parens p = P.try_ (P.char '(') *> p <* P.char ')'
let add = P.char '+' *> P.return (+)
let sub = P.char '-' *> P.return (-)
let mul = P.char '*' *> P.return ( * )
let div = P.char '/' *> P.return ( / )
let integer =
  P.chars1_if (function '0'..'9'->true|_->false) >|= int_of_string

let chainl1 e op =
  P.fix (fun r ->
    e >>= fun x -> P.try_ (op <*> P.return x <*> r) <|> P.return x)

let expr : int P.t =
  P.fix (fun expr ->
    let factor = parens expr <|> integer in
    let term = chainl1 factor (mul <|> div) in
    chainl1 term (add <|> sub))
```

Now we can parse strings using `expr`:

```ocaml
# P.parse_string expr "4*1+2";; (* Ok 6 *)
- : int P.or_error = Result.Ok 6

# P.parse_string expr "4*(1+2)";; (* Ok 12 *)
- : int P.or_error = Result.Ok 12
```