1
- # Motivation
2
- Previously we have a fixed set of mode names in the parser. Everytime we want to
3
- add more modes we need to update the parser (and correspondingly ocamlformat).
4
- This is too costy in the long term.
5
-
6
- We introduce a new mode syntax that allows mode names (and mode expressions in
7
- the future) to enjoy a dedicated name space. As a result, any identifier can be
8
- used as a mode name.
9
-
10
1
# Modes and modalities
11
2
Currently a mode expression is simply a space-delimited list of modes.
12
3
@@ -23,112 +14,120 @@ local
23
14
local unique
24
15
```
25
16
26
- Currently modalities have the same syntax as modes:
17
+ Modes are in a dedicated namespace separated from variable names or type names,
18
+ which means you can continue to use ` local ` or ` unique ` as variable or type
19
+ names.
20
+
21
+ Currently a modality expression is simply a space-delimited list of modalities.
27
22
28
23
```
29
24
modality := local | global | ..
30
25
modalities := separated_nonempty_list(SPACE, modality)
31
26
```
27
+ Similarly, modalities are in a dedicated namespace.
32
28
33
29
# Where can they appear
34
30
35
- Mode expressions and modalities can appear after either ` @ ` or ` @@ ` . The former
36
- is used in most cases, while the latter is used for disambiguition. For example,
37
- in ` val f : a -> b @ global ` , the ` @ global ` could be annotating either ` b ` or
38
- ` f ` . To avoid the ambiguity, we will write ` val f : a -> b @ local @@ global `
39
- where ` local ` is the mode of ` b ` and ` global ` is the modality on ` f ` .
31
+ To write a mode expression in program, it has to be prefixed by an ` @ ` symbol.
32
+ Similarly, a modality expression has to be prefixed by an ` @@ ` symbol. They can
33
+ appear in several places in a program as described below.
40
34
41
- ## Function parameter
42
- ``` ocaml
43
- let foo ?(label_let_pattern = default) = ..
44
- let foo ~(label_let_pattern) = ..
45
- let foo (x @ modes) = ..
46
- let foo (x : ty @@ modes) = ..
47
- ```
48
- where ` label_let_pattern ` could be
35
+ ## Arrow types
49
36
``` ocaml
50
- x @ modes
51
- x : ty @@ modes
52
- x : a b c. a -> b -> c @@ modes
53
- ```
54
- Patterns that are not directly function parameters can’t have modes. For
55
- example:
56
- ```
57
- let foo ((x, y) @ modes) = .. (error)
37
+ a * b @ modes -> b @ modes
38
+ foo:a * b @ modes -> b @ modes
39
+ ?foo:a * b @ modes -> b @ modes
58
40
```
59
41
60
- ## Let bindings
42
+ One should be careful about the precedence of ` @ ` . In the following example,
43
+ ` modes ` annotates ` c ` .
61
44
``` ocaml
62
- let x @ modes = ..
63
- let x : ty @@ modes = ..
64
- let x : type a b. ty @@ modes = ..
45
+ a -> b -> c @ modes
65
46
```
66
47
67
- ## Functions and their return
48
+ You can use parentheses to override precedence. In the
49
+ following example, ` modes ` annotates ` b -> c ` .
68
50
``` ocaml
69
- let (foo @ modes) x y = ..
70
- let foo x y @ modes = ..
71
- let foo x y : ty @@ modes = ..
72
- fun foo x y @ modes -> ..
73
- fun foo x y : ty @@ modes -> ..
51
+ a -> (b -> c) @ modes
74
52
```
75
53
76
- ## Arrow types
54
+ ## Function parameter
55
+ The rule of thumb is: wherever a type constraint ` x : ty ` is allowed, a similar
56
+ mode constraint ` x @ modes ` or type-and-mode constraint ` x : ty @ modes ` will be
57
+ allowed.
77
58
``` ocaml
78
- a * b @ modes -> b @ modes
79
- foo:a * b @ modes -> b @ modes
80
- ?foo:a * b @ modes -> b @ modes
59
+ let foo ?(x : int @ modes = default) = ..
60
+ let foo ?x:((a, b) : int @ modes = default)
61
+ let foo ~(x : int @ modes) = ..
62
+ let foo ~x:((a, b) : int @ modes) = ..
63
+ let foo ((a, b) : int @ modes) = ..
81
64
```
82
-
83
- ## Record fields & Value descriptions
84
- The two are similar in both semantics and syntax, so we will consider them
85
- together.
65
+ Patterns that are not directly function parameters can’t have modes. For
66
+ example, the following is not allowed, because ` x @ local ` is not a function
67
+ parameter (but the first component of one).
86
68
``` ocaml
87
- type r = {x : string @@ global}
88
- type r = {x : string @ local -> string @ local @@ global}
89
-
90
- val foo : string -> string @ local @@ portable
69
+ let foo ((x @ local), y) = ..
91
70
```
92
71
93
- ## Expressions
72
+ Again, one should pay attention to the precedences. In the following example, the first
73
+ ` modes ` annotates ` 'b ` , while the second annotates ` x ` .
94
74
``` ocaml
95
- (expression : _ @@ local)
75
+ let foo (x : 'a -> 'b @ modes) = ..
76
+ let foo (x : ('a -> 'b) @ modes) = ..
96
77
```
97
78
98
- # Future works
99
- ## Unzipped syntax
100
- In the future we will support
101
- ``` ocaml
102
- type r = string -> string @@ local unique -> unique local
103
- ```
104
- which corresponds to
79
+ ## Let bindings
80
+ The rule of thumb is: wherever a type constraint ` pat : ty ` is allowed, a similar
81
+ mode constraint ` pat @ modes ` and type-and-mode constraint ` pat : ty @ modes ` will be
82
+ allowed.
105
83
``` ocaml
106
- type r = string @@ local unique -> string @@ unique local
84
+ let a : int @ modes = 42 in
85
+ let (a, b) : int @ once portable = 42 in
107
86
```
108
- This gets more complex when modalities are involved:
87
+
88
+ ## Functions and their body
89
+ You can specify the mode of the function itself:
109
90
``` ocaml
110
- type r = { x : string -> string @@ (local -> unique) global}
91
+ let (foo @ modes) x y = ..
111
92
```
112
- which is equivalent to
93
+ You can also specify the mode of the function body:
113
94
``` ocaml
114
- type r = {x : string @ local -> string @ unique @@ global}
95
+ let foo x y @ modes = ..
96
+ let foo x y : ty @ modes = ..
97
+ fun foo x y @ modes -> ..
115
98
```
116
- where ` global ` is a modality on the ` x ` field.
99
+ We don't support ` fun foo x y : ty @ modes -> 42 ` due to a limitation in the
100
+ parser.
117
101
118
- ## Syntax sugar
119
- Similar to
102
+ ## Expressions
120
103
``` ocaml
121
- let foo x y : int = exp in
104
+ (expression : ty @ local)
122
105
```
123
- which unfolds to
106
+ We don't support ` (expression @ modes) ` because ` @ ` is already parsed as a binary operator.
107
+
108
+ ## Record fields
109
+ Record fields can have modalities, for example:
124
110
``` ocaml
125
- let foo x y = exp : int in
111
+ type r = {x : string @@ modalities}
112
+ type r = {x : string @ modes -> string @ modes @@ modalities}
126
113
```
127
- We should allow
114
+
115
+ ## Signature items
116
+ Signature items such as values can have modalities; for example:
128
117
``` ocaml
129
- let foo x y @ local = exp in
118
+ val foo : string @@ modalities
119
+ val bar : string @ modes -> string @ modes @@ modalities
130
120
```
131
- unfold to
121
+
122
+ A signature can have default modalities that each item can override; for example:
132
123
``` ocaml
133
- let foo x y = exp : _ @@ local in
124
+ sig @@ portable
125
+ val foo : string (* have portable modality *)
126
+ val bar : string -> string @@ nonportable (* not have portable modality *)
127
+ end
134
128
```
129
+
130
+ ## Modules
131
+ Support for modules with modes is being worked on and not ready for company-wide adoption.
132
+ For the few use sites, the syntax should be self-explanatory. More documentation will come
133
+ as it becomes ready.
0 commit comments