Skip to content

Commit 1f173db

Browse files
authored
Merge pull request #10663 from LPTK/polymorphic-function-types-doc
2 parents 7adb69d + d8da6c3 commit 1f173db

File tree

4 files changed

+101
-7
lines changed

4 files changed

+101
-7
lines changed

docs/docs/reference/new-types/dependent-function-types.md

+5-6
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,16 @@ layout: doc-page
33
title: "Dependent Function Types"
44
---
55

6-
A dependent function type describes functions where the result type may depend
7-
on the function's parameter values. Example:
6+
A dependent function type is a function type whose result depends
7+
on the function's parameters. For example:
88
```scala
99
trait Entry { type Key; val key: Key }
1010

1111
def extractKey(e: Entry): e.Key = e.key // a dependent method
12+
1213
val extractor: (e: Entry) => e.Key = extractKey // a dependent function value
13-
// ║ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ║
14-
// ║ Dependent ║
15-
// ║ Function Type ║
16-
// ╚═══════════════════╝
14+
// ^^^^^^^^^^^^^^^^^^^
15+
// a dependent function type
1716
```
1817
Scala already has _dependent methods_, i.e. methods where the result
1918
type refers to some of the parameters of the method. Method
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
---
2+
layout: doc-page
3+
title: "Polymorphic Function Types"
4+
---
5+
6+
A polymorphic function type is a function type which accepts type parameters.
7+
For example:
8+
```scala
9+
// A polymorphic method:
10+
def foo[A](xs: List[A]): List[A] = xs.reverse
11+
12+
// A polymorphic function value:
13+
val bar: [A] => List[A] => List[A]
14+
// ^^^^^^^^^^^^^^^^^^^^^^^^^
15+
// a polymorphic function type
16+
= [A] => (xs: List[A]) => foo[A](xs)
17+
```
18+
Scala already has _polymorphic methods_, i.e. methods which accepts type parameters.
19+
Method `foo` above is an example, accepting a type parameter `A`.
20+
So far, it
21+
was not possible to turn such methods into polymorphic function values like `bar` above,
22+
which can be passed as parameters to other functions, or returned as results.
23+
24+
In Dotty this is now possible. The type of the `bar` value above is
25+
26+
```scala
27+
[A] => List[A] => List[A]
28+
```
29+
30+
This type describes function values which take a type `A` as a parameter,
31+
then take a list of type `List[A]`, and return a list of the same type `List[A]`.
32+
33+
[More details](https://github.com/lampepfl/dotty/pull/4672)
34+
35+
36+
### Example Usage
37+
38+
Polymorphic function type are particularly useful
39+
when callers of a method are required to provide a
40+
function which has to be polymorphic,
41+
meaning that it should accept arbitrary types as part of its inputs.
42+
43+
For instance, consider the situation where we have
44+
a data type to represent the expressions of a simple language
45+
(consisting only of variables and function application)
46+
in a strongly-typed way:
47+
48+
```scala
49+
enum Expr[A]:
50+
case Var(name: String)
51+
case Apply[A, B](fun: Expr[B => A], arg: Expr[B]) extends Expr[A]
52+
```
53+
54+
We would like to provide a way for users to map a function
55+
over all immediate subexpressions of a given `Expr`.
56+
This requires the given function to be polymorphic,
57+
since each subexpression may have a different type.
58+
Here is how to implement this using polymorphic function types:
59+
60+
```scala
61+
def mapSubexpressions[A](e: Expr[A])(f: [B] => Expr[B] => Expr[B]): Expr[A] =
62+
e match
63+
case Apply(fun, arg) => Apply(f(fun), f(arg))
64+
case Var(n) => Var(n)
65+
```
66+
67+
And here is how to use this function to _wrap_ each subexpression
68+
in a given expression with a call to some `wrap` function,
69+
defined as a variable:
70+
71+
```scala
72+
val e0 = Apply(Var("f"), Var("a"))
73+
val e1 = mapSubexpressions(e0)(
74+
[B] => (se: Expr[B]) => Apply(Var[B => B]("wrap"), se))
75+
println(e1) // Apply(Apply(Var(wrap),Var(f)),Apply(Var(wrap),Var(a)))
76+
```
77+
78+
79+
80+
### Relationship With Type Lambdas
81+
82+
Polymorphic function types are not to be confused with
83+
[_type lambdas_](new-types/type-lambdas.md).
84+
While the former describes the _type_ of a polymorphic _value_,
85+
the latter is an actual function value _at the type level_.
86+
87+
A good way of understanding the difference is to notice that
88+
**_type lambdas are applied in types,
89+
whereas polymorphic functions are applied in terms_**:
90+
One would call the function `bar` above
91+
by passing it a type argument `bar[Int]` _within a method body_.
92+
On the other hand, given a type lambda such as `type F = [A] =>> List[A]`,
93+
one would call `F` _withing a type expression_, as in `type Bar = F[Int]`.

docs/docs/reference/overview.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ These are additions to the language that make it more powerful or pleasant to us
107107
- [Enums](enums/enums.md) provide concise syntax for enumerations and [algebraic data types](enums/adts.md).
108108
- [Parameter Untupling](other-new-features/parameter-untupling.md) avoids having to use `case` for tupled parameter destructuring.
109109
- [Dependent Function Types](new-types/dependent-function-types.md) generalize dependent methods to dependent function values and types.
110-
- [Polymorphic Function Types](https://github.com/lampepfl/dotty/pull/4672) generalize polymorphic methods to dependent function values and types. _Current status_: There is a proposal, and a prototype implementation, but the implementation has not been finalized or merged yet.
110+
- [Polymorphic Function Types](new-types/polymorphic-function-types.md) generalize polymorphic methods to polymorphic function values and types. _Current status_: There is a proposal and a merged prototype implementation, but the implementation has not been finalized (it is notably missing type inference support).
111111
- [Kind Polymorphism](other-new-features/kind-polymorphism.md) allows the definition of operators working equally on types and type constructors.
112112
- [@targetName Annotations](other-new-features/targetName.md) make it easier to interoperate with code written in other languages and give more flexibility for avoiding name clashes.
113113

docs/sidebar.yml

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ sidebar:
3535
url: docs/reference/new-types/match-types.html
3636
- title: Dependent Function Types
3737
url: docs/reference/new-types/dependent-function-types.html
38+
- title: Polymorphic Function Types
39+
url: docs/reference/new-types/polymorphic-function-types.html
3840
- title: Enums
3941
subsection:
4042
- title: Enumerations

0 commit comments

Comments
 (0)