diff --git a/library/src/scala/Tuple.scala b/library/src/scala/Tuple.scala index 4219fc87ae83..ea1c9f35da98 100644 --- a/library/src/scala/Tuple.scala +++ b/library/src/scala/Tuple.scala @@ -103,12 +103,23 @@ object Tuple { case x *: xs => S[Size[xs]] } + /** Fold a tuple `(T1, ..., Tn)` into `F[T1, F[... F[Tn, Z]...]]]` */ + type Fold[T <: Tuple, Z, F[_, _]] = T match + case EmptyTuple => Z + case h *: t => F[h, Fold[t, Z, F]] + /** Converts a tuple `(T1, ..., Tn)` to `(F[T1], ..., F[Tn])` */ type Map[Tup <: Tuple, F[_]] <: Tuple = Tup match { case EmptyTuple => EmptyTuple case h *: t => F[h] *: Map[t, F] } + /** Converts a tuple `(T1, ..., Tn)` to a flattened `(..F[T1], ..., ..F[Tn])` */ + type FlatMap[Tup <: Tuple, F[_] <: Tuple] <: Tuple = Tup match { + case EmptyTuple => EmptyTuple + case h *: t => Concat[F[h], FlatMap[t, F]] + } + /** Given two tuples, `A1 *: ... *: An * At` and `B1 *: ... *: Bn *: Bt` * where at least one of `At` or `Bt` is `EmptyTuple` or `Tuple`, * returns the tuple type `(A1, B1) *: ... *: (An, Bn) *: Ct` diff --git a/tests/pos/tuple-flatmap.scala b/tests/pos/tuple-flatmap.scala new file mode 100644 index 000000000000..168d2d7bcf57 --- /dev/null +++ b/tests/pos/tuple-flatmap.scala @@ -0,0 +1,14 @@ + +type Empty[X] = EmptyTuple +type Twice[X] = (X, X) + +def test = + val a1: EmptyTuple = ??? : Tuple.FlatMap[EmptyTuple, Empty] + val a2: EmptyTuple = ??? : Tuple.FlatMap[(Int, String), Empty] + + val b1: EmptyTuple = ??? : Tuple.FlatMap[EmptyTuple, Tuple1] + val b2: (Int, String) = ??? : Tuple.FlatMap[(Int, String), Tuple1] + + val c1: EmptyTuple = ??? : Tuple.FlatMap[EmptyTuple, Twice] + val c2: (Int, Int, String, String) = ??? : Tuple.FlatMap[(Int, String), Twice] + val c3: (Int, List[Int], String, List[String]) = ??? : Tuple.FlatMap[(Int, String), [X] =>> (X, List[X])] diff --git a/tests/pos/tuple-fold.scala b/tests/pos/tuple-fold.scala new file mode 100644 index 000000000000..cf52a867ebdb --- /dev/null +++ b/tests/pos/tuple-fold.scala @@ -0,0 +1,8 @@ + +type Empty[X] = EmptyTuple +type Twice[X] = (X, X) + +def test = + val a1: EmptyTuple = ??? : Tuple.Fold[EmptyTuple, Nothing, Tuple2] + val a2: (Int, (String, Nothing)) = ??? : Tuple.Fold[(Int, String), Nothing, Tuple2] + val a3: Int | String | Char = ??? : Tuple.Fold[(Int, String, Char), Nothing, [X, Y] =>> X | Y]