forked from scala/scala3
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add spec for auto-tupling of n-ary functions
- Loading branch information
1 parent
7087a6c
commit d91fa07
Showing
3 changed files
with
86 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
--- | ||
layout: doc-page | ||
title: "Automatic Tupling of Function Parameters - More Details" | ||
--- | ||
|
||
### Motivation | ||
|
||
Say you have a list of pairs | ||
|
||
```scala | ||
val xs: List[(Int, Int)] | ||
``` | ||
|
||
and you want to map `xs` to a list of `Int`s so that each pair of numbers is mapped to their sum. | ||
Previously, the best way to do this was with a pattern-matching decomposition: | ||
```scala | ||
xs.map { | ||
case (x, y) => x + y | ||
} | ||
``` | ||
While correct, this is also inconvenient. Instead, automatic tupling of function parameters proposed to be able to write it the following way: | ||
|
||
```scala | ||
xs.map { | ||
(x, y) => x + y | ||
} | ||
``` | ||
or, equivalently: | ||
```scala | ||
xs.map(_ + _) | ||
``` | ||
|
||
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`. | ||
|
||
### Type Checking | ||
|
||
Let a function `F` of the form `F = (p1, ..., pn) => E` for `n != 1`, parameters `p1, ..., pn`, and an expression `E`. | ||
|
||
|
||
If the expected type of `F` is a fully defined function type or SAM-type that has a | ||
single parameter of a subtype of `ProductN[T1, ..., Tn]`, where each type `Ti` fits the corresponding | ||
parameter `pi`. | ||
|
||
A type `T` fits a parameter `p` if one of the following two cases is `true`: | ||
|
||
* `p` comes without a type, i.e. it is a simple identifier or `_`. | ||
* `p` is of the form `x: U` or `_: U` and `T` conforms to `U`. | ||
|
||
Auto-tupling composes with eta-expansion. That is an n-ary function generated by eta-expansion | ||
can in turn be adapted to the expected type with auto-tupling. | ||
|
||
#### Term addaptation | ||
|
||
If the a function | ||
```scala | ||
(p1: T1, ..., pn: Tn) => E | ||
``` | ||
|
||
is typed as `ProductN[T1, ..., Tn] => Te`, then it will be transformed to | ||
|
||
```scala | ||
(x: TupleN[T1, ..., Tn]) => { | ||
def p1: T1 = x._1 | ||
... | ||
def pn: Tn = x._n | ||
E | ||
} | ||
``` | ||
|
||
### Migration | ||
|
||
Code like this could not be written before, hence the new notation would not be ambigouous after addoptation. | ||
|
||
Thought it is possible that someone has written an implicit conversion for `(T1, ..., Tn) => R` into `TupleN[T1, ..., Tn]` | ||
for some `n`. This change could be detected and fixed by `Scalafix`. Furthermore, such conversion would probably | ||
be doing the same translation (semantically) but in a less efficient way. | ||
|
||
### Reference | ||
|
||
For more info see: | ||
* [Issue #897](https://github.com/lampepfl/dotty/issues/897). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters