Backport from sid to buster
[hcoop/debian/mlton.git] / doc / guide / src / TypeVariableScope.adoc
CommitLineData
7f918cf1
CE
1TypeVariableScope
2=================
3
4In <:StandardML:Standard ML>, every type variable is _scoped_ (or
5bound) at a particular point in the program. A type variable can be
6either implicitly scoped or explicitly scoped. For example, `'a` is
7implicitly scoped in
8
9[source,sml]
10----
11val id: 'a -> 'a = fn x => x
12----
13
14and is implicitly scoped in
15
16[source,sml]
17----
18val id = fn x: 'a => x
19----
20
21On the other hand, `'a` is explicitly scoped in
22
23[source,sml]
24----
25val 'a id: 'a -> 'a = fn x => x
26----
27
28and is explicitly scoped in
29
30[source,sml]
31----
32val 'a id = fn x: 'a => x
33----
34
35A type variable can be scoped at a `val` or `fun` declaration. An SML
36type checker performs scope inference on each top-level declaration to
37determine the scope of each implicitly scoped type variable. After
38scope inference, every type variable is scoped at exactly one
39enclosing `val` or `fun` declaration. Scope inference shows that the
40first and second example above are equivalent to the third and fourth
41example, respectively.
42
43Section 4.6 of the <:DefinitionOfStandardML:Definition> specifies
44precisely the scope of an implicitly scoped type variable. A free
45occurrence of a type variable `'a` in a declaration `d` is said to be
46_unguarded_ in `d` if `'a` is not part of a smaller declaration. A
47type variable `'a` is implicitly scoped at `d` if `'a` is unguarded in
48`d` and `'a` does not occur unguarded in any declaration containing
49`d`.
50
51
52== Scope inference examples ==
53
54* In this example,
55+
56[source,sml]
57----
58val id: 'a -> 'a = fn x => x
59----
60+
61`'a` is unguarded in `val id` and does not occur unguarded in any
62containing declaration. Hence, `'a` is scoped at `val id` and the
63declaration is equivalent to the following.
64+
65[source,sml]
66----
67val 'a id: 'a -> 'a = fn x => x
68----
69
70* In this example,
71+
72[source,sml]
73----
74 val f = fn x => let exception E of 'a in E x end
75----
76+
77`'a` is unguarded in `val f` and does not occur unguarded in any
78containing declaration. Hence, `'a` is scoped at `val f` and the
79declaration is equivalent to the following.
80+
81[source,sml]
82----
83val 'a f = fn x => let exception E of 'a in E x end
84----
85
86* In this example (taken from the <:DefinitionOfStandardML:Definition>),
87+
88[source,sml]
89----
90val x: int -> int = let val id: 'a -> 'a = fn z => z in id id end
91----
92+
93`'a` occurs unguarded in `val id`, but not in `val x`. Hence, `'a` is
94implicitly scoped at `val id`, and the declaration is equivalent to
95the following.
96+
97[source,sml]
98----
99val x: int -> int = let val 'a id: 'a -> 'a = fn z => z in id id end
100----
101
102
103* In this example,
104+
105[source,sml]
106----
107val f = (fn x: 'a => x) (fn y => y)
108----
109+
110`'a` occurs unguarded in `val f` and does not occur unguarded in any
111containing declaration. Hence, `'a` is implicitly scoped at `val f`,
112and the declaration is equivalent to the following.
113+
114[source,sml]
115----
116val 'a f = (fn x: 'a => x) (fn y => y)
117----
118+
119This does not type check due to the <:ValueRestriction:>.
120
121* In this example,
122+
123[source,sml]
124----
125fun f x =
126 let
127 fun g (y: 'a) = if true then x else y
128 in
129 g x
130 end
131----
132+
133`'a` occurs unguarded in `fun g`, not in `fun f`. Hence, `'a` is
134implicitly scoped at `fun g`, and the declaration is equivalent to
135+
136[source,sml]
137----
138fun f x =
139 let
140 fun 'a g (y: 'a) = if true then x else y
141 in
142 g x
143 end
144----
145+
146This fails to type check because `x` and `y` must have the same type,
147but the `x` occurs outside the scope of the type variable `'a`. MLton
148reports the following error.
149+
150----
151Error: z.sml 3.21-3.41.
152 Then and else branches disagree.
153 then: [???]
154 else: ['a]
155 in: if true then x else y
156 note: type would escape its scope: 'a
157 escape to: z.sml 1.1-6.5
158----
159+
160This problem could be fixed either by adding an explicit type
161constraint, as in `fun f (x: 'a)`, or by explicitly scoping `'a`, as
162in `fun 'a f x = ...`.
163
164
165== Restrictions on type variable scope ==
166
167It is not allowed to scope a type variable within a declaration in
168which it is already in scope (see the last restriction listed on page
1699 of the <:DefinitionOfStandardML:Definition>). For example, the
170following program is invalid.
171
172[source,sml]
173----
174fun 'a f (x: 'a) =
175 let
176 fun 'a g (y: 'a) = y
177 in
178 ()
179 end
180----
181
182MLton reports the following error.
183
184----
185Error: z.sml 3.11-3.12.
186 Type variable scoped at an outer declaration: 'a.
187 scoped at: z.sml 1.1-6.6
188----
189
190This is an error even if the scoping is implicit. That is, the
191following program is invalid as well.
192
193[source,sml]
194----
195fun f (x: 'a) =
196 let
197 fun 'a g (y: 'a) = y
198 in
199 ()
200 end
201----