|
| 1 | +--- |
| 2 | +layout: doc-page |
| 3 | +title: "Tupled Function" |
| 4 | +--- |
| 5 | + |
| 6 | +Tupled Function |
| 7 | +---------------------- |
| 8 | + |
| 9 | +With functions bounded to arities up to 22 it was possible to generalize some operation on all function types using overloading. |
| 10 | +Now that we have functions and tuples generalized to [arities above 22](https://dotty.epfl.ch/docs/reference/dropped-features/limit22.html) overloading is not an option anymore. |
| 11 | +The type class `TupleFunction` provides a way to abstract directly over a function of any arity converting it to an equivalent function that receives all arguments in a single tuple. |
| 12 | + |
| 13 | +```scala |
| 14 | +/** Type class relating a `FunctionN[..., R]` with an equivalent tupled function `Function1[TupleN[...], R]` |
| 15 | + * |
| 16 | + * @tparam F a function type |
| 17 | + * @tparam G a tupled function type (function of arity 1 receiving a tuple as argument) |
| 18 | + */ |
| 19 | +@implicitNotFound("${F} cannot be tupled as ${G}") |
| 20 | +sealed trait TupledFunction[F, G] { |
| 21 | + def tupled(f: F): G |
| 22 | + def untupled(g: G): F |
| 23 | +} |
| 24 | +``` |
| 25 | + |
| 26 | +The compiler will synthesize an instance of `TupledFunction[F, G]` if: |
| 27 | + |
| 28 | +* `F` is a function type of arity `N` |
| 29 | +* `G` is a function with a single tuple argument of size `N` and it's types are equal to the arguments of `F` |
| 30 | +* The return type of `F` is equal to the return type of `G` |
| 31 | +* `F` and `G` are the same kind of function (both are `(...) => R` or both are `given (...) => R`) |
| 32 | +* If only one of `F` or `G` is instantiated the second one is inferred. |
| 33 | + |
| 34 | +Examples |
| 35 | +-------- |
| 36 | +`TupledFunction` can be used to generalize the `Function1.tupled`, ... `Function22.tupled` methods to functions of any arities ([full example](https://github.com/lampepfl/dotty/tests/run/tupled-function-tupled.scala)) |
| 37 | + |
| 38 | +```scala |
| 39 | +/** Creates a tupled version of this function: instead of N arguments, |
| 40 | + * it accepts a single [[scala.Tuple]] argument. |
| 41 | + * |
| 42 | + * @tparam F the function type |
| 43 | + * @tparam Args the tuple type with the same types as the function arguments of F |
| 44 | + * @tparam R the return type of F |
| 45 | + */ |
| 46 | +def (f: F) tupled[F, Args <: Tuple, R] given (tf: TupledFunction[F, Args => R]): Args => R = tf.tupled(f) |
| 47 | +``` |
| 48 | + |
| 49 | +`TupledFunction` can be used to generalize the `Function.untupled` methods to functions of any arities ([full example](https://github.com/lampepfl/dotty/tests/run/tupled-function-untupled.scala)) |
| 50 | + |
| 51 | +```scala |
| 52 | +/** Creates an untupled version of this function: instead of single [[scala.Tuple]] argument, |
| 53 | + * it accepts a N arguments. |
| 54 | + * |
| 55 | + * This is a generalization of [[scala.Function.untupled]] that work on functions of any arity |
| 56 | + * |
| 57 | + * @tparam F the function type |
| 58 | + * @tparam Args the tuple type with the same types as the function arguments of F |
| 59 | + * @tparam R the return type of F |
| 60 | + */ |
| 61 | +def (f: Args => R) untupled[F, Args <: Tuple, R] given (tf: TupledFunction[F, Args => R]): F = tf.untupled(f) |
| 62 | +``` |
| 63 | + |
| 64 | +`TupledFunction` can also be used to generalize the [`Tuple1.compose`](https://github.com/lampepfl/dotty/tests/run/tupled-function-compose.scala) and [`Tuple1.andThen`](https://github.com/lampepfl/dotty/tests/run/tupled-function-andThen.scala) methods to compose functions of larger arities and with functions that return tuples. |
| 65 | + |
| 66 | +```scala |
| 67 | +/** Composes two instances of TupledFunctions in a new TupledFunctions, with this function applied last |
| 68 | + * |
| 69 | + * @tparam F a function type |
| 70 | + * @tparam G a function type |
| 71 | + * @tparam FArgs the tuple type with the same types as the function arguments of F and return type of G |
| 72 | + * @tparam GArgs the tuple type with the same types as the function arguments of G |
| 73 | + * @tparam R the return type of F |
| 74 | + */ |
| 75 | +def (f: F) compose[F, G, FArgs <: Tuple, GArgs <: Tuple, R](g: G) given (tg: TupledFunction[G, GArgs => FArgs], tf: TupledFunction[F, FArgs => R]): GArgs => R = { |
| 76 | + (x: GArgs) => tf.tupled(f)(tg.tupled(g)(x)) |
| 77 | +} |
| 78 | +``` |
0 commit comments