Skip to content

Commit f1036d7

Browse files
committed
First rewriting
1 parent 9f334ee commit f1036d7

File tree

1 file changed

+36
-39
lines changed

1 file changed

+36
-39
lines changed

docs/_docs/reference/contextual/derivation.md

Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,15 @@ given [T: Show] : Show[Tree[T]] = Show.derived
2727
We say that `Tree` is the _deriving type_ and that the `Eq`, `Ordering` and `Show` instances are _derived instances_.
2828

2929
## Exact mechanism
30-
More formally, for a class/trait/object/enum `DerivingType[T_1, ..., T_N] derives TC` (if `DerivingType` does not take parameters, we define `N = 0`), a derived instance is created in `DerivingType`'s companion object (or `DerivingType` itself if it is an object)
30+
More formally, for a class/trait/object/enum `DerivingType[T_1, ..., T_N] derives TC`, a derived instance is created in `DerivingType`'s companion object (or `DerivingType` itself if it is an object).
31+
If `DerivingType` does not take parameters, we define `N = 0`.
3132

32-
What the derived instance looks like depends on the specifics of `DerivingType` and `TC`, first the arity of `TC`:
33+
What the derived instance looks like depends on the specifics of `DerivingType` and `TC`, but the general shape is as follows:
34+
```scala
35+
given [...]: TC[ ... DerivingType[...] ... ] = TC.derived
36+
```
37+
38+
The first condition is the arity of `TC`:
3339

3440
### `TC` takes 1 parameter
3541

@@ -46,58 +52,60 @@ If `N == 0`, we understand the above to mean:
4652
```scala
4753
given TC[DerivingType] = TC.derived
4854
```
55+
#### `F` and `DerivingType` have parameters of matching kind on the right
56+
This section concers cases where you can pair arguments of `F` and `DerivingType` starting from the right such that they have the same kinds pairwise, and all arguments of `F` or `DerivingType` (or both) are used up.
57+
We also add the requirement that `F` have at least one parameter.
58+
59+
The general shape will then be:
60+
```scala
61+
given [...]: TC[[...] => DerivingType[...]] = TC.derived
62+
```
63+
Where of course `TC` and `DerivingType` are applied to types of the correct kind.
4964

50-
<!-- #### You can pair arguments of `F` and `DerivingType` starting from the right such that they have the same kinds pairwise, and all arguments of at least one of them are used up -->
51-
#### `F` and `DerivingType` have their `m` rightmost arguments which have the same kind pairwise and `N >= 0`, `K > 0`, and `m == N` and/or `m == K`
65+
To make this work, we split it into 3 cases:
5266

5367
The generated instance is then:
54-
If `m == N == K`:
68+
If `TC` and `DerivingType` take the same number of arguments (`N == K`):
5569
```scala
5670
given TC[DerivingType] = TC.derived
71+
// simplified form of:
72+
// given TC[[A_1, ..., A_K] => DerivingType[A_1, ..., A_K]] = TC.derived
5773
```
58-
If `m == N < K`:
74+
If `DerivingType` takes less arguments than `TC` (`N < K`), we throw away the leftmost ones:
5975
```scala
6076
given TC[[A_1, ..., A_K] =>> DerivingType[A_(K-N+1), ..., A_K]] = TC.derived
61-
```
6277

63-
TODO: Speak about `N == 0` being allowed, since then `(K-N+1) > K`
78+
// if DerivingType takes no arguments (N == 0), the above simplifies to:
79+
given TC[[A_1, ..., A_K] =>> DerivingType] = TC.derived
80+
```
6481

65-
If `m == K < N`:
82+
If `TC` takes less arguments than `DerivingType` (`K < N`), we fill in the leftmost slots with type parameters:
6683
```scala
6784
given [T_1, ... T_(N-K)]: TC[[A_1, ..., A_K] =>> DerivingType[T_1, ... T_(N-K), A_1, ..., A_K]] = TC.derived
6885
```
6986

7087
### `TC` takes 2 parameters
7188

7289
Is `TC` the `CanEqual` type class ?
73-
If yes, proceed as follows, otherwise go to [`TC` is not valid for automatic derivation](#tc-is-not-valid-for-automatic-derivation)
90+
If yes, proceed as follows, otherwise go to [`TC` is not valid for automatic derivation](#tc-is-not-valid-for-automatic-derivation).
7491

75-
We have therefore: `DerivingType[T_1, ..., T_N] derives CanEqual`
92+
We have therefore: `DerivingType[T_1, ..., T_N] derives CanEqual`.
7693

77-
TODO: Talk about higher kinded types
94+
Let `U_1`, ..., `U_M` be the parameters of `DerivingType` of kind `*`.
7895

79-
And the generated instance is:
96+
The generated instance is then:
8097
```scala
81-
given [T_1L, T_1R, ..., T_NL, T_NR]
82-
(using CanEqual[T_1L, T_1R], ..., CanEqual[T_NL, T_NR]):
83-
CanEqual[DerivingType[T_1L, ..., T_NL], DerivingType[T_1R, ..., T_NR]] =
98+
given [T_1L, T_1R, ..., T_NL, T_NR] // every parameter of DerivingType twice
99+
(using CanEqual[U_1L, U_1R], ..., CanEqual[U_NL, U_NR]): // only parameters of Deriving type with kind *
100+
CanEqual[DerivingType[T_1L, ..., T_NL], DerivingType[T_1R, ..., T_NR]] = // again, every parameter
84101
CanEqual.derived
85102
```
86103

104+
The bounds of `T_i`s are handled correctly, for example: `T_2 <: T_1` becomes `T_2L <: T_1L`.
105+
87106
### `TC` is not valid for automatic derivation
88107

89108
Throw some error.
90-
<!--
91-
More formally, for a class/trait/object/enum `DerivingType derives TC`, the following given instance is created in `DerivingType`'s companion object (or `DerivingType` itself if it is an object):
92-
* if `DerivingType` doesn't have type parameters
93-
```scala
94-
given TC[DerivingType] = TC.derived
95-
```
96-
* if `DerivingType` has type parameters `[T_1, ..., T_N]`
97-
```scala
98-
given [T_1: TC, ... T_N: TC]: TC[DerivingType[T_1, ..., T_N]] = TC.derived
99-
```
100-
-->
101109

102110
`TC.derived` should be an expression that conforms to the expected type `TC[DerivingType]`, potentially elaborated using term and/or type inference.
103111

@@ -111,18 +119,7 @@ given [T: Ordering]: Ordering[Option[T]] = Ordering.derived
111119

112120
It is discouraged to directly refer to the `derived` member if you can use a `derives` clause instead.
113121

114-
#### CanEqual
115-
116-
With `DerivingType[T_1, ..., T_N] derives CanEqual`, the following instance is created:
117-
118-
```scala
119-
given [T_1L, T_1R, ..., T_NL, T_NR]
120-
(using CanEqual[T_1L, T_1R], ..., CanEqual[T_NL, T_NR]):
121-
CanEqual[DerivingType[T_1L, ..., T_NL], DerivingType[T_1R, ..., T_NR]] =
122-
CanEqual.derived
123-
```
124-
125-
All data types can have a `derives` clause. This document focuses primarily on data types which also have a given instance
122+
All data types can have a `derives` clause. The rest of this document focuses primarily on data types which also have a given instance
126123
of the `Mirror` type class available.
127124

128125
## `Mirror`

0 commit comments

Comments
 (0)