|
| 1 | +--- |
| 2 | +layout: doc-page |
| 3 | +title: "Automatic Tupling of Function Parameters - More Details" |
| 4 | +--- |
| 5 | + |
| 6 | +### Motivation |
| 7 | + |
| 8 | +Say you have a list of pairs |
| 9 | + |
| 10 | +```scala |
| 11 | +val xs: List[(Int, Int)] |
| 12 | +``` |
| 13 | + |
| 14 | +and you want to map `xs` to a list of `Int`s so that each pair of numbers is mapped to their sum. |
| 15 | +Previously, the best way to do this was with a pattern-matching decomposition: |
| 16 | +```scala |
| 17 | +xs.map { |
| 18 | + case (x, y) => x + y |
| 19 | +} |
| 20 | +``` |
| 21 | +While correct, this is also inconvenient. Instead, automatic tupling of function parameters proposed to be able to write it the following way: |
| 22 | + |
| 23 | +```scala |
| 24 | +xs.map { |
| 25 | + (x, y) => x + y |
| 26 | +} |
| 27 | +``` |
| 28 | +or, equivalently: |
| 29 | +```scala |
| 30 | +xs.map(_ + _) |
| 31 | +``` |
| 32 | + |
| 33 | +Generally, a function value with `n > 1` parameters can be converted to a pattern-matching closure using case if the expected type is a unary function type of the form `((T_1, ..., T_n)) => U`. |
| 34 | + |
| 35 | +### Type Checking |
| 36 | + |
| 37 | +Let a function `F` of the form `F = (p1, ..., pn) => E` for `n != 1`, parameters `p1, ..., pn`, and an expression `E`. |
| 38 | + |
| 39 | + |
| 40 | +If the expected type of `F` is a fully defined function type or SAM-type that has a |
| 41 | +single parameter of a subtype of `ProductN[T1, ..., Tn]`, where each type `Ti` fits the corresponding |
| 42 | +parameter `pi`. |
| 43 | + |
| 44 | +A type `T` fits a parameter `p` if one of the following two cases is `true`: |
| 45 | + |
| 46 | +* `p` comes without a type, i.e. it is a simple identifier or `_`. |
| 47 | +* `p` is of the form `x: U` or `_: U` and `T` conforms to `U`. |
| 48 | + |
| 49 | +Auto-tupling composes with eta-expansion. That is an n-ary function generated by eta-expansion |
| 50 | +can in turn be adapted to the expected type with auto-tupling. |
| 51 | + |
| 52 | +#### Term addaptation |
| 53 | + |
| 54 | +If the a function |
| 55 | +```scala |
| 56 | +(p1: T1, ..., pn: Tn) => E |
| 57 | +``` |
| 58 | + |
| 59 | +is typed as `ProductN[T1, ..., Tn] => Te`, then it will be transformed to |
| 60 | + |
| 61 | +```scala |
| 62 | +(x: TupleN[T1, ..., Tn]) => { |
| 63 | + def p1: T1 = x._1 |
| 64 | + ... |
| 65 | + def pn: Tn = x._n |
| 66 | + E |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +### Migration |
| 71 | + |
| 72 | +Code like this could not be written before, hence the new notation would not be ambigouous after addoptation. |
| 73 | + |
| 74 | +Thought it is possible that someone has written an implicit conversion for `(T1, ..., Tn) => R` into `TupleN[T1, ..., Tn]` |
| 75 | +for some `n`. This change could be detected and fixed by `Scalafix`. Furthermore, such conversion would probably |
| 76 | +be doing the same translation (semantically) but in a less efficient way. |
| 77 | + |
| 78 | +### Reference |
| 79 | + |
| 80 | +For more info see: |
| 81 | +* [Issue #897](https://github.com/lampepfl/dotty/issues/897). |
0 commit comments