Skip to content

Commit da8b362

Browse files
committed
Improvements to Tuple
Improve organization and doc comments
1 parent 4df97c8 commit da8b362

File tree

1 file changed

+91
-82
lines changed

1 file changed

+91
-82
lines changed

library/src/scala/Tuple.scala

Lines changed: 91 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import compiletime.*
55
import compiletime.ops.int.*
66

77
/** Tuple of arbitrary arity */
8-
sealed trait Tuple extends Product {
8+
sealed trait Tuple extends Product:
99
import Tuple.*
1010

1111
/** Create a copy of this tuple as an Array */
@@ -84,66 +84,90 @@ sealed trait Tuple extends Product {
8484
inline def reverse[This >: this.type <: Tuple]: Reverse[This] =
8585
runtime.Tuples.reverse(this).asInstanceOf[Reverse[This]]
8686

87-
/** A tuple with the fields of this tuple in reversed order added in front of `acc` */
87+
/** A tuple with the elements of this tuple in reversed order added in front of `acc` */
8888
inline def reverseOnto[This >: this.type <: Tuple, Acc <: Tuple](acc: Acc): ReverseOnto[This, Acc] =
8989
(this.reverse ++ acc).asInstanceOf[ReverseOnto[This, Acc]]
9090

9191
/** A tuple consisting of all elements of this tuple that have types
92-
* for which the given predicate `P` evaluates to truye.
92+
* for which the given type level predicate `P` reduces to the literal
93+
* constant `true`.
9394
*/
9495
inline def filter[This >: this.type <: Tuple, P[_] <: Boolean]: Filter[This, P] =
9596
val toInclude = constValueTuple[IndicesWhere[This, P]].toArray
9697
val arr = new Array[Object](toInclude.length)
9798
for i <- 0 until toInclude.length do
9899
arr(i) = this.productElement(toInclude(i).asInstanceOf[Int]).asInstanceOf[Object]
99100
Tuple.fromArray(arr).asInstanceOf[Filter[This, P]]
100-
}
101101

102-
object Tuple {
102+
object Tuple:
103103

104-
/** Type of a tuple with an element appended */
105-
type Append[X <: Tuple, Y] <: NonEmptyTuple = X match {
106-
case EmptyTuple => Y *: EmptyTuple
107-
case x *: xs => x *: Append[xs, Y]
108-
}
104+
/** The size of a tuple, represented as a literal constant subtype of Int */
105+
type Size[X <: Tuple] <: Int = X match
106+
case EmptyTuple => 0
107+
case x *: xs => S[Size[xs]]
108+
109+
/** The type of the element at position N in the tuple X */
110+
type Elem[X <: Tuple, N <: Int] = X match
111+
case x *: xs =>
112+
N match
113+
case 0 => x
114+
case S[n1] => Elem[xs, n1]
109115

110-
/** Type of the head of a tuple */
111-
type Head[X <: NonEmptyTuple] = X match {
116+
/** The type of the first element of a tuple */
117+
type Head[X <: NonEmptyTuple] = X match
112118
case x *: _ => x
113-
}
114119

115-
/** Type of the initial part of the tuple without its last element */
116-
type Init[X <: Tuple] <: Tuple = X match {
120+
/** The type of the last element of a tuple */
121+
type Last[X <: Tuple] = X match
122+
case x *: EmptyTuple => x
123+
case _ *: xs => Last[xs]
124+
125+
/** The type of a tuple consisting of all elements of tuple X except the first one */
126+
type Tail[X <: NonEmptyTuple] <: Tuple = X match
127+
case _ *: xs => xs
128+
129+
/** The type of the initial part of a tuple without its last element */
130+
type Init[X <: Tuple] <: Tuple = X match
117131
case _ *: EmptyTuple => EmptyTuple
118132
case x *: xs =>
119133
x *: Init[xs]
120-
}
121134

122-
/** Type of the tail of a tuple */
123-
type Tail[X <: NonEmptyTuple] <: Tuple = X match {
124-
case _ *: xs => xs
135+
/** The type of the tuple consisting of the first `N` elements of `X`,
136+
* or all elements if `N` exceeds `Size[X]`.
137+
*/
138+
type Take[X <: Tuple, N <: Int] <: Tuple = N match
139+
case 0 => EmptyTuple
140+
case S[n1] => X match
141+
case EmptyTuple => EmptyTuple
142+
case x *: xs => x *: Take[xs, n1]
143+
144+
/** The type of the tuple consisting of all elements of `X` except the first `N` ones,
145+
* or no elements if `N` exceeds `Size[X]`.
146+
*/
147+
type Drop[X <: Tuple, N <: Int] <: Tuple = N match {
148+
case 0 => X
149+
case S[n1] => X match {
150+
case EmptyTuple => EmptyTuple
151+
case x *: xs => Drop[xs, n1]
152+
}
125153
}
126154

127-
/** Type of the last element of a tuple */
128-
type Last[X <: Tuple] = X match {
129-
case x *: EmptyTuple => x
130-
case _ *: xs => Last[xs]
155+
/** Type of a tuple with an element appended */
156+
type Append[X <: Tuple, Y] <: NonEmptyTuple = X match {
157+
case EmptyTuple => Y *: EmptyTuple
158+
case x *: xs => x *: Append[xs, Y]
131159
}
132160

133-
/** Type of the concatenation of two tuples */
134-
type Concat[X <: Tuple, +Y <: Tuple] <: Tuple = X match {
161+
/** The pair type `(Take(X, N), Drop[X, N]). */
162+
type Split[X <: Tuple, N <: Int] = (Take[X, N], Drop[X, N])
163+
164+
/** Type of the concatenation of two tuples `X` and `Y` */
165+
type Concat[X <: Tuple, +Y <: Tuple] <: Tuple = X match
135166
case EmptyTuple => Y
136167
case x1 *: xs1 => x1 *: Concat[xs1, Y]
137-
}
138168

139-
/** Type of the element at position N in the tuple X */
140-
type Elem[X <: Tuple, N <: Int] = X match {
141-
case x *: xs =>
142-
N match {
143-
case 0 => x
144-
case S[n1] => Elem[xs, n1]
145-
}
146-
}
169+
/** An infix shorthand for `Concat[X, Y]` */
170+
infix type ++[X <: Tuple, +Y <: Tuple] = Concat[X, Y]
147171

148172
/** The index of `Y` in tuple `X` as a literal constant Int,
149173
* or `Size[X]` if `Y` does not occur in `X`
@@ -153,31 +177,30 @@ object Tuple {
153177
case x *: xs => S[IndexOf[xs, Y]]
154178
case EmptyTuple => 0
155179

156-
/** Literal constant Int size of a tuple */
157-
type Size[X <: Tuple] <: Int = X match {
158-
case EmptyTuple => 0
159-
case x *: xs => S[Size[xs]]
160-
}
161-
162180
/** Fold a tuple `(T1, ..., Tn)` into `F[T1, F[... F[Tn, Z]...]]]` */
163181
type Fold[Tup <: Tuple, Z, F[_, _]] = Tup match
164182
case EmptyTuple => Z
165183
case h *: t => F[h, Fold[t, Z, F]]
166184

167-
/** Converts a tuple `(T1, ..., Tn)` to `(F[T1], ..., F[Tn])` */
168-
type Map[Tup <: Tuple, F[_ <: Union[Tup]]] <: Tuple = Tup match {
185+
/** The type of tuple `X` mapped with the type-level function `F`.
186+
* If `X = (T1, ..., Ti)` then `Map[X, F] = `(F[T1], ..., F[Ti])`.
187+
*/
188+
type Map[Tup <: Tuple, F[_ <: Union[Tup]]] <: Tuple = Tup match
169189
case EmptyTuple => EmptyTuple
170190
case h *: t => F[h] *: Map[t, F]
171-
}
172191

173-
/** Converts a tuple `(T1, ..., Tn)` to a flattened `(..F[T1], ..., ..F[Tn])` */
174-
type FlatMap[Tup <: Tuple, F[_ <: Union[Tup]] <: Tuple] <: Tuple = Tup match {
192+
/** The type of tuple `X` flat-mapped with the type-level function `F`.
193+
* If `X = (T1, ..., Ti)` then `FlatMap[X, F] = `F[T1] ++ ... ++ F[Ti]`
194+
*/
195+
type FlatMap[Tup <: Tuple, F[_ <: Union[Tup]] <: Tuple] <: Tuple = Tup match
175196
case EmptyTuple => EmptyTuple
176197
case h *: t => Concat[F[h], FlatMap[t, F]]
177-
}
198+
// TODO: implement term level analogue
178199

179-
/** Filters out those members of the tuple for which the predicate `P` returns `false`.
180-
* A predicate `P[X]` is a type that can be either `true` or `false`. For example:
200+
/** The type of the tuple consisting of all elements of tuple `X` that have types
201+
* for which the given type level predicate `P` reduces to the literal
202+
* constant `true`. A predicate `P[X]` is a type that can be either `true`
203+
* or `false`. For example:
181204
* ```scala
182205
* type IsString[x] <: Boolean = x match {
183206
* case String => true
@@ -187,31 +210,38 @@ object Tuple {
187210
* ```
188211
* @syntax markdown
189212
*/
190-
type Filter[Tup <: Tuple, P[_] <: Boolean] <: Tuple = Tup match {
213+
type Filter[X <: Tuple, P[_] <: Boolean] <: Tuple = X match
191214
case EmptyTuple => EmptyTuple
192-
case h *: t => P[h] match {
215+
case h *: t => P[h] match
193216
case true => h *: Filter[t, P]
194217
case false => Filter[t, P]
195-
}
196-
}
197218

198219
/** A tuple consisting of those indices `N` of tuple `X` where the predicate `P`
199220
* is true for `Elem[X, N]`. Indices are type level values <: Int.
200221
*/
201222
type IndicesWhere[X <: Tuple, P[_] <: Boolean] =
202223
helpers.IndicesWhereHelper[X, P, 0]
203224

204-
/** Given two tuples, `A1 *: ... *: An * At` and `B1 *: ... *: Bn *: Bt`
205-
* where at least one of `At` or `Bt` is `EmptyTuple` or `Tuple`,
206-
* returns the tuple type `(A1, B1) *: ... *: (An, Bn) *: Ct`
207-
* where `Ct` is `EmptyTuple` if `At` or `Bt` is `EmptyTuple`, otherwise `Ct` is `Tuple`.
225+
/** The type of the tuple consisting of all element values of
226+
* tuple `X` zipped with corresponding elements of tuple `Y`.
227+
* If the two tuples have different sizes,
228+
* the extra elements of the larger tuple will be disregarded.
229+
* For example, if
230+
* ```
231+
* X = (S1, ..., Si)
232+
* Y = (T1, ..., Tj) where j >= i
233+
* ```
234+
* then
235+
* ```
236+
* Zip[X, Y] = ((S1, T1), ..., (Si, Ti))
237+
* ```
238+
* @syntax markdown
208239
*/
209-
type Zip[T1 <: Tuple, T2 <: Tuple] <: Tuple = (T1, T2) match {
240+
type Zip[T1 <: Tuple, T2 <: Tuple] <: Tuple = (T1, T2) match
210241
case (h1 *: t1, h2 *: t2) => (h1, h2) *: Zip[t1, t2]
211242
case (EmptyTuple, _) => EmptyTuple
212243
case (_, EmptyTuple) => EmptyTuple
213244
case _ => Tuple
214-
}
215245

216246
/** Converts a tuple `(F[T1], ..., F[Tn])` to `(T1, ... Tn)` */
217247
type InverseMap[X <: Tuple, F[_]] <: Tuple = X match {
@@ -226,36 +256,15 @@ object Tuple {
226256
*/
227257
type IsMappedBy[F[_]] = [X <: Tuple] =>> X =:= Map[InverseMap[X, F], F]
228258

229-
/** A tuple with the fields of tuple `X` in reversed order */
259+
/** A tuple with the elements of tuple `X` in reversed order */
230260
type Reverse[X <: Tuple] = ReverseOnto[X, EmptyTuple]
231261

232-
/** A tuple with the fields of tuple `X` in reversed order added in front of `Acc` */
262+
/** A tuple with the elements of tuple `X` in reversed order added in front of `Acc` */
233263
type ReverseOnto[X <: Tuple, Acc <: Tuple] <: Tuple = X match
234264
case x *: xs => ReverseOnto[xs, x *: Acc]
235265
case EmptyTuple => Acc
236266

237-
/** Transforms a tuple `(T1, ..., Tn)` into `(T1, ..., Ti)`. */
238-
type Take[T <: Tuple, N <: Int] <: Tuple = N match {
239-
case 0 => EmptyTuple
240-
case S[n1] => T match {
241-
case EmptyTuple => EmptyTuple
242-
case x *: xs => x *: Take[xs, n1]
243-
}
244-
}
245-
246-
/** Transforms a tuple `(T1, ..., Tn)` into `(Ti+1, ..., Tn)`. */
247-
type Drop[T <: Tuple, N <: Int] <: Tuple = N match {
248-
case 0 => T
249-
case S[n1] => T match {
250-
case EmptyTuple => EmptyTuple
251-
case x *: xs => Drop[xs, n1]
252-
}
253-
}
254267

255-
/** Splits a tuple (T1, ..., Tn) into a pair of two tuples `(T1, ..., Ti)` and
256-
* `(Ti+1, ..., Tn)`.
257-
*/
258-
type Split[T <: Tuple, N <: Int] = (Take[T, N], Drop[T, N])
259268

260269
/** Given a tuple `(T1, ..., Tn)`, returns a union of its
261270
* member types: `T1 | ... | Tn`. Returns `Nothing` if the tuple is empty.
@@ -377,7 +386,7 @@ object Tuple {
377386
case false => IndicesWhereHelper[t, P, S[N]]
378387

379388
end helpers
380-
}
389+
end Tuple
381390

382391
/** A tuple of 0 elements */
383392
type EmptyTuple = EmptyTuple.type

0 commit comments

Comments
 (0)