Skip to content

Commit 9ba5508

Browse files
authored
flambda-backend: Document our extensions (#2365)
Document features The added docs are pasted from our internal documentation. I've reviewed to make sure we aren't leaking secrets or internal links. Further review not required; this text has already been reviewed.
1 parent 0f4d23e commit 9ba5508

File tree

3 files changed

+248
-0
lines changed

3 files changed

+248
-0
lines changed

jane/doc/include-functor.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# The `include functor` extension
2+
3+
The `include functor` extension eliminates a common source of boilerplate when
4+
defining modules that include the results of functors. It adds the module item
5+
form `include functor F`, where `F` must be a functor whose parameter can be
6+
"filled in" with the previous contents of the module. For example, you can now
7+
write this:
8+
9+
```ocaml
10+
module M = struct
11+
type t = ...
12+
[@@deriving compare, sexp]
13+
14+
include functor Comparable.Make
15+
end
16+
```
17+
18+
Traditionally, this would have required defining an inner structure `T` just to
19+
have something the functor can be applied to:
20+
21+
```ocaml
22+
module M = struct
23+
module T = struct
24+
type t = ...
25+
[@@deriving compare, sexp]
26+
end
27+
28+
include T
29+
include Comparable.Make(T)
30+
end
31+
```
32+
33+
These two code fragments behave identically, except that in the first case the
34+
module `M` won't have a submodule `T`.
35+
36+
The feature can also be used in signatures:
37+
38+
```ocaml
39+
module type F = functor (T : sig ... end) -> Comparable.S with type t = T.t
40+
41+
module type S = sig
42+
type t
43+
[@@deriving compare, sexp]
44+
45+
include functor F
46+
end
47+
```
48+
49+
This behaves as if we had written:
50+
51+
```ocaml
52+
module type S = sig
53+
type t
54+
[@@deriving compare, sexp]
55+
56+
include Comparable.S with type t := t
57+
end
58+
```
59+
60+
Currently it's uncommon to define functor module types like `F` (there's no such
61+
module type in `Comparable`, for example). However, you can get the module type
62+
of a functor directly with `module type of`, so the previous signature could
63+
equivalently be written:
64+
65+
```ocaml
66+
module type S = sig
67+
type t
68+
[@@deriving compare, sexp]
69+
70+
include functor module type of Comparable.Make
71+
end
72+
```
73+
74+
## Details and Limitations
75+
76+
This extension is not available in the upstream compiler, so publicly
77+
released code should not use it. We plan to upstream it in the
78+
future.
79+
80+
To include a functor `F`, it must have a module type of the form:
81+
82+
```ocaml
83+
F : S1 -> S2
84+
```
85+
86+
or
87+
88+
```ocaml
89+
F : S1 -> () -> S2
90+
```
91+
92+
where `S1` and `S2` are signatures.
93+
94+
Currently, `include functor` cannot be used in the signatures of recursive
95+
modules. It may be possible to lift this restriction in the future, if there is
96+
sufficient demand.

jane/doc/labeled-tuples.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# Labeled tuples
2+
3+
The *labeled tuples* extension allows you to label tuple elements. It is
4+
conceptually dual to labeled function arguments, allowing you to give a helpful
5+
name to constructed values where labeled function arguments permit giving a
6+
helpful name to parameters.
7+
8+
Here is a motivating example
9+
where we want to compute two values from a list and be careful
10+
not to mix them up:
11+
12+
```ocaml
13+
let sum_and_product ints =
14+
let init = ~sum:0, ~product:1 in
15+
List.fold_left ints ~init ~f:(fun (~sum, ~product) elem ->
16+
let sum = elem + sum in
17+
let product = elem * product in
18+
~sum, ~product)
19+
```
20+
21+
This example shows the use of labeled tuples in types and patterns. They may be
22+
punned like record elements / function arguments.
23+
24+
In types, tuple labels are written similarly to function argument labels. For
25+
example, the function `f` in the previous example has the type:
26+
27+
```ocaml
28+
(sum:int * product:int) -> int -> sum:int * product:int
29+
```
30+
31+
Labeled tuples are useful anytime you want to use names to explain or
32+
disambiguate the elements of a tuple, but declaring a new record feels too
33+
heavy. As another example, consider this function from `Core_unix` which
34+
creates a pipe with descriptors for reading and writing:
35+
36+
```ocaml
37+
val pipe : ?close_on_exec:bool -> unit -> File_descr.t * File_descr.t
38+
```
39+
40+
Which is which? While it's possible declaring a new record might be best in
41+
this case, we can now use labeled tuples:
42+
43+
```ocaml
44+
val pipe : ?close_on_exec:bool -> unit -> read:File_descr.t * write:File_descr.t
45+
```
46+
47+
Tuples may be partially labeled, which can be useful when some elements of the
48+
tuple share a type and need disambiguation, but others don't. For example:
49+
```ocaml
50+
type min_max_avg = min:int * max:int * float
51+
```
52+
53+
## Reordering and partial patterns
54+
55+
Like records, labeled tuple patterns may be reordered or partial. The compiler
56+
only supports reordering / partial matching when it knows the type of the
57+
pattern from its context.
58+
59+
So, for example, we can write:
60+
```ocaml
61+
# let lt = ~x:0, ~y:42;;
62+
val lt : x:int * y:int = (~x:0, ~y:42)
63+
64+
# let twice_y = let ~y, .. = lt in y * 2;;
65+
val twice_y : int = 84
66+
```
67+
68+
When the type is not known (in the same sense that we require a type to be known
69+
to disambiguate among constructors), the compiler will reject a partial pattern. For
70+
example, this program
71+
72+
```ocaml
73+
let get_y t =
74+
let ~y, .. = t in
75+
y
76+
```
77+
78+
is rejected with this error:
79+
80+
```
81+
File "foo.ml", line 2, characters 8-14:
82+
2 | let ~y, .. = t in
83+
^^^^^^
84+
Error: Could not determine the type of this partial tuple pattern.
85+
```
86+
87+
This example could be fixed by adding a type annotation to the function's
88+
parameter.
89+
90+
Labels may also be repeated in a tuple, and unlabeled elements can be thought of
91+
as all sharing the same unique label. When matching on such a tuple, the first
92+
occurence of a label in the pattern is bound to the first corresponding label in
93+
the value, and so on. As a result, it's also now possible to partially match on
94+
an unlabeled tuple to retrieve the first few elements.
95+
96+
## Limitations
97+
98+
Parentheses are necessary to disambiguate functions types with labeled arguments
99+
from function types with labeled tuple arguments when the first element of the
100+
tuple has a label. `ocamlformat` will handle this for you.
101+
102+
Unlike records, reordering is not supported in labeled tuple expressions, even
103+
when the type is known. This is like how the function definition for a function
104+
with labeled arguments must bind the arguments in the same order as the type.
105+
106+
Labeled tuples do not support projection (extracting an element of the tuple
107+
by label).
108+
109+
Structure-level let bindings do not allow reordering / partial matching as
110+
flexibly as expression-level let bindings. For example, this program does not
111+
typecheck:
112+
113+
```ocaml
114+
module M = struct
115+
let lt = ~x:0, ~y:42
116+
let ~y, .. = lt
117+
end
118+
```
119+
120+
It results in the error:
121+
122+
```
123+
File "foo.ml", line 3, characters 6-12:
124+
3 | let ~y, .. = lt
125+
^^^^^^
126+
Error: Could not determine the type of this partial tuple pattern.
127+
```

jane/doc/module-strengthening.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# The `module strengthening` extension
2+
3+
What is the type of module `M` in this tiny program?
4+
5+
```ocaml
6+
module type S = sig type t end
7+
8+
module M : S
9+
```
10+
11+
If you said `S` then you are only partially correct: we also need to keep track
12+
of the fact that all type declarations inside it (just `t` in this example) come
13+
from `M`. So the type that the compiler infers is actually stronger:
14+
15+
```ocaml
16+
sig type t = M.t end
17+
```
18+
19+
We call this type "`S` strengthened with `M`". It can be written out explicitly
20+
as above and this is, in fact, the only way to write it without `-extension
21+
module_strengthening`. The new extension allows this type to be written as `S
22+
with M`.
23+
24+
The main motivation for this work are compiler performance improvements, which
25+
use this new form internally.

0 commit comments

Comments
 (0)