Tuples transformations

This is mini project to transform tuple and its types.

It's Scala 3 only.

To install

libraryDependencies += "io.github.mercurievv.minuscles" % "tuples-transformers" % "0.2.1"

Use import

import io.github.mercurievv.minuscles.tuples.transformers.all.*

Let's create some input data:

val input: ((Int, Long), (String, (Boolean, Double, Char), (Float, Byte))) = ((1, 2L), ("3", (true, 0.5D, "6".charAt(0)), (0.7F, 0x8)))
// input: Tuple2[Tuple2[Int, Long], Tuple3[String, Tuple3[Boolean, Double, Char], Tuple2[Float, Byte]]] = (
//   (1, 2L),
//   ("3", (true, 0.5, '6'), (0.7F, 8))
// )

Now we will do some transformations:

Flattening, Nesting

val flatten: (Int, Long, String, Boolean, Double, Char, Float, Byte) = input.toFlatten
// flatten: Tuple8[Int, Long, String, Boolean, Double, Char, Float, Byte] = (
//   1,
//   2L,
//   "3",
//   true,
//   0.5,
//   '6',
//   0.7F,
//   8
// )
val flattenToNested: (Int, (Long, (String, (Boolean, (Double, (Char, (Float, Byte))))))) = flatToNestedR(flatten)
// flattenToNested: Tuple2[Int, Tuple2[Long, Tuple2[String, Tuple2[Boolean, Tuple2[Double, Tuple2[Char, Tuple2[Float, Byte]]]]]]] = (
//   1,
//   (2L, ("3", (true, (0.5, ('6', (0.7F, 8))))))
// )
//flatToNested method works correctly only with flattened tuples, but in such cases it should save some CPU
val nested: (Int, (Long, (String, (Boolean, (Double, (Char, (Float, Byte))))))) = input.toNestedR
// nested: Tuple2[Int, Tuple2[Long, Tuple2[String, Tuple2[Boolean, Tuple2[Double, Tuple2[Char, Tuple2[Float, Byte]]]]]]] = (
//   1,
//   (2L, ("3", (true, (0.5, ('6', (0.7F, 8))))))
// )

Two Elements Swap

Swapping 2 elements of tuple.

val swapped: (Int, Boolean, String, Long, Double, Char, Float, Byte) = flatten.swap(2, 4)
// swapped: Tuple8[Int, Boolean, String, Long, Double, Char, Float, Byte] = (
//   1,
//   true,
//   "3",
//   2L,
//   0.5,
//   '6',
//   0.7F,
//   8
// )

Unflatten

Reconstruct the original nested structure from a flat tuple.

val fromFlattenV: ((Int, Long), (String, (Boolean, Double, Char), (Float, Byte))) = fromFlatten[((Int, Long), (String, (Boolean, Double, Char), (Float, Byte)))](flatten)
// fromFlattenV: Tuple2[Tuple2[Int, Long], Tuple3[String, Tuple3[Boolean, Double, Char], Tuple2[Float, Byte]]] = (
//   (1, 2L),
//   ("3", (true, 0.5, '6'), (0.7F, 8))
// )

From Nested-Right

Reconstruct the original structure from a nested-right tuple.

val fromNested: ((Int, Long), (String, (Boolean, Double, Char), (Float, Byte))) = fromNestedR[((Int, Long), (String, (Boolean, Double, Char), (Float, Byte)))](nested)
// fromNested: Tuple2[Tuple2[Int, Long], Tuple3[String, Tuple3[Boolean, Double, Char], Tuple2[Float, Byte]]] = (
//   (1, 2L),
//   ("3", (true, 0.5, '6'), (0.7F, 8))
// )

Reorder by Type

Reorder tuple elements by specifying the desired output type. All element types must be unique.

val t = ("hello", 42, 3.14)
// t: Tuple3[String, Int, Double] = ("hello", 42, 3.14)
val reordered: (Int, Double, String) = reorder[(String, Int, Double), (Int, Double, String)](t)
// reordered: Tuple3[Int, Double, String] = (42, 3.14, "hello")
val reorderedExt: (Int, Double, String) = t.reorderTo[(Int, Double, String)]
// reorderedExt: Tuple3[Int, Double, String] = (42, 3.14, "hello")

Duplicate types in the source are rejected at compile time:

val bad: (String, Int, String) = ("a", 1, "b")
reorder[(String, Int, String), (Int, String)](bad)
// error:
// No given instance of type io.github.mercurievv.minuscles.tuples.transformers.all.IsDistinct[(String, Int,
//   String)] was found for parameter d of method reorder in object all.
// I found:
// 
//     io.github.mercurievv.minuscles.tuples.transformers.all.IsDistinct.consDistinct[
//       String, (Int, String)](
//       /* missing */
//         summon[
//           scala.util.NotGiven[
//             io.github.mercurievv.minuscles.tuples.transformers.all.TupleIndex[
//               (Int, String), String]
//           ]
//         ]
//       ,
//     ???)
// 
// But no implicit values were found that match type scala.util.NotGiven[
//   io.github.mercurievv.minuscles.tuples.transformers.all.TupleIndex[
//     (Int, String), String]
// ].
// reorder[(String, Int, String), (Int, String)](bad)
//                                                  ^

Distinct types constraint

IsDistinct[T] is a typeclass witness that all element types in T are unique. It is used automatically by reorder/reorderTo, but can also be used as a constraint in your own code.

Require a distinct tuple at a call site:

val distinct = t.requireDistinct  // compiles — (String, Int, Double) has unique types
// distinct: Tuple3[String, Int, Double] = ("hello", 42, 3.14)
val bad2: (String, Int, String) = ("a", 1, "b")
bad2.requireDistinct
// error:
// value requireDistinct is not a member of (String, Int, String).
// An extension method was tried, but could not be fully constructed:
// 
//     io.github.mercurievv.minuscles.tuples.transformers.all.requireDistinct[
//       (String, Int, String)](repl.MdocSession.MdocApp.bad2)(
//       io.github.mercurievv.minuscles.tuples.transformers.all.IsDistinct.consDistinct
//         [String, (Int, String)](
//         /* missing */
//           summon[
//             scala.util.NotGiven[
//               io.github.mercurievv.minuscles.tuples.transformers.all.TupleIndex[
//                 (Int, String), String]
//             ]
//           ]
//         ,
//       ???)
//     )
// 
//     failed with:
// 
//         No given instance of type io.github.mercurievv.minuscles.tuples.transformers.all.IsDistinct[
//           (String, Int, String)] was found for parameter x$2 of method requireDistinct in object all.
//         I found:
//         
//             io.github.mercurievv.minuscles.tuples.transformers.all.IsDistinct.consDistinct[
//               String, (Int, String)](
//               /* missing */
//                 summon[
//                   scala.util.NotGiven[
//                     io.github.mercurievv.minuscles.tuples.transformers.all.TupleIndex[
//                       (Int, String), String]
//                   ]
//                 ]
//               ,
//             ???)
//         
//         But no implicit values were found that match type scala.util.NotGiven[
//           io.github.mercurievv.minuscles.tuples.transformers.all.TupleIndex[
//             (Int, String), String]
//         ].
// bad2.requireDistinct
// ^^^^^^^^^^^^^^^^^^^^

Use as a constraint in your own function:

def processDistinct[T <: Tuple](t: T)(using IsDistinct[T]): String = t.toString