├── Makefile
├── README.md
├── containers.dot
├── data.dot
└── images
├── containers.png
└── data.png
/Makefile:
--------------------------------------------------------------------------------
1 | build_dir = ./images
2 | outputs = $(build_dir)/containers.png $(build_dir)/data.png
3 |
4 | font = "JetBrainsMono"
5 | node_color = "\#f5f7ff"
6 | line_color = "\#5e6687"
7 |
8 | all: $(outputs)
9 |
10 | $(outputs): $(build_dir)/%.png: %.dot
11 | circo -Gfontname=$(font) -Nfontname=$(font) -Efontname=$(font) -Nstyle="filled" \
12 | -Nfillcolor=$(node_color) -Ncolor=$(line_color) -Nfontcolor=$(line_color) \
13 | -Ecolor=$(line_color) -Efontcolor=$(line_color) \
14 | -Tsvg $< > tmp.svg && convert -density 200 tmp.svg $@
15 | rm tmp.svg
16 |
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Converting between standard OCaml types
2 |
3 | The OCaml standard library provides many convertion functions of the form
4 | `Foo.{to,of}_bar` between its various types. These are incomplete – and somewhat
5 | arbitrary – so it's often necessary to go via intermediate types to achieve the
6 | convertion you want. (Either that or roll your own with a `fold` or `iter`
7 | function.)
8 |
9 | What's worse, you may need to mix forwards and backwards conversions (`to_` and
10 | `of_` style respectively), requiring you to search both forwards and backwards
11 | in the documentation to get the conversion you need. For example, consider the
12 | case of `('k, 'v) Hashtbl.t -> ('k * 'v) list`:
13 |
14 | 1. Looking in the docs for [`Hashtbl`][hashtbl-doc], we see that there's no
15 | direct conversion to an association list. We might give up and build our own
16 | one with `Hashtbl.fold`. On OCaml 4.07+, we have `Hashtbl.to_seq : ('k, 'v) Hashtbl.t -> ('k, 'v) Seq.t`, so let's start by using that.
17 |
18 | 1. We look in the docs for [`Seq`][seq-doc], and find no conversions. Once again,
19 | we could use get distracted and use `Seq.fold_left` to build our own. Or, we
20 | could start searching backwards from the type we want...
21 |
22 | 1. In the docs for [`List`][list-doc], we find the function `List.of_seq : 'a Seq.t -> 'a List.t`. Now we can complete the chain:
23 |
24 | ```ocaml
25 | let hashtbl_to_list h = Hashtbl.to_seq h |> List.of_seq
26 | ```
27 |
28 | Rather than keeping the entire Stdlib documentation open in browser tabs, it can
29 | be helpful to view all of the available conversions as a directed graph. That's
30 | what this repository provides. (These graphs show the conversions available on
31 | OCaml 4.11.0; your mileage may vary.)
32 |
33 | [hashtbl-doc]: https://caml.inria.fr/pub/docs/manual-ocaml/libref/Hashtbl.html
34 | [seq-doc]: https://caml.inria.fr/pub/docs/manual-ocaml/libref/Seq.html
35 | [list-doc]: https://caml.inria.fr/pub/docs/manual-ocaml/libref/List.html
36 |
37 | ## Container types
38 |
39 | 
40 |
41 | Take-aways:
42 |
43 | - The common containers are ordered by:
44 |
45 | - `Array` ⊏ `List` ⊏ `Seq`
46 | - `Buffer` ⊏ `Bytes` ⊏ `String` ⊏ `Seq`
47 | - {`Hashtbl`, `Map`, `Queue`, `Set`, `Stack`} ⊏ `Seq`
48 |
49 | - To convert between containers `Foo.t` → `Bar.t`, it's usually necessary to go
50 | via `Seq.t` with `Foo.to_seq >> Bar.of_seq`.
51 |
52 | - There's no direct conversion between `float Array.t` and `Float.Array.t`.
53 |
54 | ## Data types
55 |
56 | 
57 |
58 | Take-aways:
59 |
60 | - The numeric modules are ordered by `Int64` ⊏ `Nativeint` ⊏ `Int32` ⊏ {`Int`,
61 | `Float`}. When coercing between them, you should check modules in this order.
62 |
--------------------------------------------------------------------------------
/containers.dot:
--------------------------------------------------------------------------------
1 | digraph {
2 | graph [pad="0.5", nodesep="0.25", ranksep="0.85"];
3 | node [color="#5e6687", shape="box"];
4 | edge [color="#5e6687", arrowhead="empty"];
5 |
6 | subgraph cluster_legend {
7 | node [fillcolor=none, shape=plaintext]
8 | key [label=<
9 | Foo.to_bar |
10 | Bar.of_foo |
11 |
>]
12 | key2 [label=<>]
16 | key:i1:e -> key2:i1:w [color=green]
17 | key:i2:e -> key2:i2:w [color=red]
18 | }
19 |
20 |
21 | // List
22 | List -> Seq [color=green]
23 | Seq -> List [color=red]
24 |
25 | // Array
26 | Array -> List [color=green]
27 | Array -> Seq [color=green]
28 | List -> Array [color=red]
29 | Seq -> Array [color=red]
30 |
31 | // Float.Array
32 | "Float.Array" -> List [color=green]
33 | "Float.Array" -> Seq [color=green]
34 | List -> "Float.Array" [color=red]
35 | Seq -> "Float.Array" [color=red]
36 |
37 | // Hashtbl
38 | Hashtbl -> Seq [color=green]
39 | Seq -> Hashtbl [color=red]
40 |
41 | // Map
42 | Map -> Seq [color=green]
43 | Seq -> Map [color=red]
44 |
45 | // Set
46 | Set -> Seq [color=green]
47 | List -> Set [color=red]
48 | Seq -> Set [color=red]
49 |
50 | // Bytes
51 | Bytes -> Seq [color=green]
52 | Bytes -> String [color=green]
53 | String -> Bytes [color=red]
54 | Seq -> Bytes [color=red]
55 |
56 | // Buffer
57 | Buffer -> Bytes [color=green]
58 | Buffer -> Seq [color=green]
59 | Seq -> Buffer [color=red]
60 |
61 | // Bigarray
62 | Array -> Bigarray [color=red]
63 |
64 | // Stack
65 | Stack -> Seq [color=green]
66 | Seq -> Stack [color=red]
67 |
68 | // Stream
69 | List -> Stream [color=red]
70 | String -> Stream [color=red]
71 | Bytes -> Stream [color=red]
72 |
73 | // String
74 | String -> Seq [color=green]
75 | Seq -> String [color=red]
76 |
77 | // Result
78 | Result -> List [color=green]
79 | Result -> Option [color=green]
80 | Result -> Seq [color=green]
81 |
82 | // Queue
83 | Queue -> Seq [color=green]
84 | Seq -> Queue [color=red]
85 |
86 | // Option
87 | Option -> Result [color=green]
88 | Option -> List [color=green]
89 | Option -> Seq [color=green]
90 | }
91 |
--------------------------------------------------------------------------------
/data.dot:
--------------------------------------------------------------------------------
1 | digraph {
2 | graph [pad="0.5", nodesep="0.25", ranksep="0.85"];
3 | node [color="#5e6687", shape="box"];
4 | edge [color="#5e6687", arrowhead="empty", arrowtail="empty"];
5 |
6 | subgraph cluster_legend {
7 | node [fillcolor=none, shape=plaintext]
8 | key [label=<
9 | Foo.to_bar |
10 | Bar.of_foo |
11 | (partial) |
12 |
>]
13 | key2 [label=<>]
18 | key:i1:e -> key2:i1:w [color=green]
19 | key:i2:e -> key2:i2:w [color=red]
20 | key:i3:e -> key2:i3:w [style=dashed]
21 | }
22 |
23 | // Int & Float
24 | Int -> Float [color=green, dir=both]
25 | Float -> Int [color=red, dir=both]
26 |
27 | // Int32
28 | Int32 -> Int [color=green]
29 | Int32 -> Float [color=green]
30 | Int -> Int32 [color=red]
31 | Float -> Int32 [color=red]
32 |
33 | // Int64
34 | Int64 -> Int [color=green]
35 | Int64 -> Int32 [color=green]
36 | Int64 -> Nativeint [color=green]
37 | Int64 -> Float [color=green]
38 | Int -> Int64 [color=red]
39 | Int32 -> Int64 [color=red]
40 | Nativeint -> Int64 [color=red]
41 | Float -> Int64 [color=red]
42 |
43 | // Nativeint
44 | Nativeint -> Int [color=green]
45 | Nativeint -> Int32 [color=green]
46 | Nativeint -> Float [color=green]
47 | Int -> Nativeint [color=red]
48 | Int32 -> Nativeint [color=red]
49 | Float -> Nativeint [color=red]
50 |
51 | // Char
52 | Char -> Int [color=green]
53 | Int -> Char [style=dashed, color=red]
54 |
55 | // Bool
56 | Bool -> Int [color=green]
57 | Bool -> Float [color=green]
58 |
59 | // Bytes
60 |
61 | // Uchar
62 | Uchar -> Int [color=green]
63 | Uchar -> Char [style=dashed, color=green]
64 | Int -> Uchar [style=dashed, color=red]
65 | Char -> Uchar [color=red]
66 |
67 | // Unit
68 | }
69 |
--------------------------------------------------------------------------------
/images/containers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/craigfe/ocaml-stdlib-type-conversions/9b257f90f4b84bc3a342a6656b25f63aeaf1beba/images/containers.png
--------------------------------------------------------------------------------
/images/data.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/craigfe/ocaml-stdlib-type-conversions/9b257f90f4b84bc3a342a6656b25f63aeaf1beba/images/data.png
--------------------------------------------------------------------------------