Skip to content

Commit b98d798

Browse files
Fixing remaining feedback
1 parent 05ac308 commit b98d798

File tree

1 file changed

+15
-11
lines changed

1 file changed

+15
-11
lines changed

pages/docs/manual/v12.0.0/generalized-algebraic-data-types.mdx

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,13 @@ we try to return a standard timezone from this function. Actually, this seems li
9191
we still want to be able to match on all cases of the variant sometimes, and a naive attempt at this will not pass the type checker. A naive example will fail:
9292

9393
```res example
94-
let convertToDaylight = tz => {
94+
let convertToDaylight = tz =>
9595
switch tz {
9696
| EST => EDT
9797
| CST => CDT
9898
| CDT => CDT
9999
| EDT => EDT
100100
}
101-
}
102101
```
103102

104103
This will complain that `daylight` and `standard` are incompatible. To fix this, we need to explicitly annotate to tell the compiler to accept both:
@@ -107,11 +106,14 @@ This will complain that `daylight` and `standard` are incompatible. To fix this,
107106
let convertToDaylight : type a. timezone<a> => timezone<daylight> = // ...
108107
```
109108

110-
`type a.` here defines a _locally abstract type_ which basically tells the compiler that the type parameter a is some specific type, but we don't care what it is. The cost of the extra specificity and safety that GADTs give us is that the compiler is not able to help us with type inference as much.
109+
The syntax `type a.` here defines a _locally abstract type_ which basically tells the compiler that the type parameter a is some specific type, but we don't care what it is. The cost of the extra specificity and safety that
110+
GADTs give us is that the compiler less able to help us with type inference.
111111

112112
## Varying return type
113113

114-
Sometimes, a function should have a different return type based on what you give it, and GADTs are how we can do this in a type-safe way. We can implement a generic `add` function that works on both `int` or `float`:
114+
Sometimes, a function should have a different return type based on what you give it, and GADTs are how we can do this in a type-safe way. We can implement a generic `add` function[^1] that works on both `int` or `float`:
115+
116+
[^1]: In ReScript v12, the built-in operators are already generic, but we use them in this example for simplicity.
115117

116118
```res example
117119
type rec number<_> = Int(int): number<int> | Float(float): number<float>
@@ -131,7 +133,9 @@ let bar = add(Int(1), Float(2.0)) // the compiler will complain here
131133

132134
How does this work? The key thing is the function signature for add. The `number` GADT is acting as a _type witness_. We have told the compiler that the type parameter for `number` will be the same as the type we return -- both are set to `a`. So if we provide a `number<int>`, `a` equals `int`, and the function will therefore return an `int`.
133135

134-
We can also use this to avoid returning `option` unnecessarily. This example is adapted from Real World Ocaml, chapter 9. We create an array searching function can be configured to either raise an exception, return an `option`, or provide a `default` value depending on the behavior we want.
136+
We can also use this to avoid returning `option` unnecessarily. We create an array searching function which either raises an exception, returns an `option`, or provides a `default` value depending on the behavior we ask for.[^2]
137+
138+
[^2]: This example is adapted from [here](https://dev.realworldocaml.org/gadts.html).
135139

136140
```res example
137141
module If_not_found = {
@@ -171,7 +175,7 @@ In an advanced case that combines the above techniques, we can use GADTs to sele
171175
The below example defines a `num` type similar to our above addition example, but this lets us use `int` and `float` arrays
172176
interchangeably, hiding the implementation type rather than exposing it. This is similar to a regular variant. However, it is a tuple including embedding a `numTy` and another value.
173177
`numTy` serves as a type-witness, making it
174-
possible to recover type information that was hidden dynamically. Matching on `numTy` will "reveal" the type of the other value in the pair.We can use this to write a generic sum function over arrays of numbers:
178+
possible to recover type information that was hidden dynamically. Matching on `numTy` will "reveal" the type of the other value in the pair. We can use this to write a generic sum function over arrays of numbers:
175179

176180
```res example
177181
type rec numTy<'a> =
@@ -197,8 +201,8 @@ Javascript libraries that are highly polymorphic or use inheritance can benefit
197201
of Node's `Stream` API.
198202

199203
This API has a method for binding event handlers, `on`. This takes an event and a callback. The callback accepts different parameters
200-
depending in which event we are binding to. A naive implementation might look similar to this, defining a
201-
separate method for each stream event to wrap the unsafe version of on.
204+
depending on which event we are binding to. A naive implementation might look similar to this, defining a
205+
separate method for each stream event to wrap the unsafe version of `on`.
202206

203207
```res example
204208
module Stream = {
@@ -223,7 +227,7 @@ the type signature of the callback and pass this instead of a plain string.
223227
Additionally, we use some type parameters to represent the different types of Streams.
224228

225229
This example is complex, but it enforces tons of useful rules. The wrong event can never be used
226-
with the wrong callback, but it also will never be used with the wrong kind of stream. The compiler will complain for example if we try to use a `Pipe` event with anything other than a `writable` stream.
230+
with the wrong callback, but it also will never be used with the wrong kind of stream. The compiler will for example complain if we try to use a `Pipe` event with anything other than a `writable` stream.
227231

228232
The real magic happens in the signature of `on`. Read it carefully, and then look at the examples and try to
229233
follow how the type variables are getting filled in, write it out on paper what each type variable is equal
@@ -242,7 +246,7 @@ module Stream = {
242246
@unboxed
243247
type chunk =
244248
| Str(string)
245-
// Node uses actually its own buffer type, but for the tutorial are just using the stdlib's buffer type.
249+
// Node uses actually its own buffer type, but for the tutorial we are using the stdlib's buffer type.
246250
| Buf(buffer)
247251
248252
type rec event<_, _> =
@@ -287,7 +291,7 @@ encounter will be more difficult to understand, and the compiler sometimes requi
287291
type your code.
288292

289293
However, there are definite situations where GADTs are the _right_ decision
290-
and will _simplify_ your code and help you avoid bugs, even rendering some bugs impossible. The `Stream` example above is a good example where the "simpler" alternative of using regular variants or even strings.
294+
and will _simplify_ your code and help you avoid bugs, even rendering some bugs impossible. The `Stream` example above is a good example where the "simpler" alternative of using regular variants or even strings
291295
would lead to a much more complex and error prone interface.
292296

293297
Ordinary variants are not necessarily _simple_ therefore, and neither are GADTs necessarily _complex_.

0 commit comments

Comments
 (0)