You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A context bound is a shorthand for expressing a common pattern of implicit parameters. For example, the `maximum` function of the last section could also have been written like this:
A bound `: C` on a type parameter `T` of a method or class indicates an inferred parameter `given C[T]`. The inferred parameter(s) generated from context bounds come last in the definition of the containing method or class. E.g.,
13
+
```
14
+
def f[T: C1 : C2, U: C3](x: T) given (y: U, z: V): R
15
+
```
16
+
would expand to
17
+
```
18
+
def f[T, U](x: T) given (y: U, z: V) given C1[T], C2[T], C3[U]: R
19
+
```
20
+
Context bounds can be combined with subtype bounds. If both are present, subtype bounds come first, e.g.
A new syntax for implicit parameters aligns definition and call syntax. Parameter definitions and method arguments both follow a `given` keyword. On the definition side, the old syntax
7
-
```scala
8
-
deff(a: A)(implicitb: B)
6
+
Functional programming tends to express most dependencies as simple functions parameterization.
7
+
This is clean and powerful, but it sometimes leads to functions that take many parameters and
8
+
call trees where the same value is passed over and over again in long call chains to many
9
+
functions. Inferable parameters can help here since they enable the compiler to synthesize
10
+
repetitive arguments instead of the programmer having to write them explicitly.
11
+
12
+
For example, given the [instance definitions](./instance-definitions.md) defined previously,
13
+
a maximum function that works for any arguments for which an ordering exists can be defined as follows:
9
14
```
10
-
is now expressed as
11
-
```scala
12
-
deff(a: A) given (b: B)
15
+
def max[T](x: T, y: T) given (ord: Ord[T]): T =
16
+
if (ord.compare(x, y) < 1) y else x
13
17
```
14
-
or, leaving out the parameter name,
15
-
```scala
16
-
deff(a: A) givenB
18
+
Here, `ord` is an _inferable parameter_. Inferable parameters are introduced with a `given` clause. Here is an example application of `max`:
19
+
```
20
+
max(2, 3) given IntOrd
17
21
```
18
-
Implicit parameters defined with the new syntax are also called _context parameters_.
19
-
They come with a matching syntax for applications: explicit arguments for context parameters are also written after a `given`.
22
+
The `given IntOrd` part provides the `IntOrd` instance as an argument for the `ord` parameter. But the point of inferable parameters is that this argument can also be left out (and usually is):
23
+
```
24
+
max(2, 3)
25
+
```
26
+
This is equally valid, and is completed by the compiler to the previous application.
20
27
21
-
The following example shows shows three methods that each have a context parameter for `Ord[T]`.
22
-
```scala
28
+
## Anonymous Inferred Parameters
29
+
30
+
In many situations, the name of an inferable parameter of a method need not be
31
+
mentioned explicitly at all, since it is only used in synthesized arguments for
32
+
other inferable parameters. In that case one can avoid defining a parameter name
33
+
and just provide its type. Example:
34
+
```
23
35
def maximum[T](xs: List[T]) given Ord[T]: T =
24
-
xs.reduceLeft((x, y) =>if (x < y) y else x)
36
+
xs.reduceLeft(max)
37
+
```
38
+
`maximum` takes an inferable parameter of type `Ord` only to pass it on as an
39
+
inferred argument to `max`. The name of the parameter is left out.
40
+
41
+
Generally, inferable parameters may be given either as a parameter list `(p_1: T_1, ..., p_n: T_n)`
42
+
or as a sequence of types, separated by commas. To distinguish the two, a leading
43
+
`(` always indicates a parameter list.
44
+
45
+
## Synthesizing Complex Inferred Arguments
25
46
47
+
Here are two other methods that have an inferable parameter of type `Ord[T]`:
48
+
```scala
26
49
defdescending[T] given (asc: Ord[T]):Ord[T] =newOrd[T] {
27
-
def (x: T) compareTo (y: T) = asc.compareTo(y)(x)
50
+
defcompare(x: T, y: T) = asc.compare(y, x)
28
51
}
29
52
30
53
defminimum[T](xs: List[T]) givenOrd[T] =
31
54
maximum(xs) givendescending
32
55
```
33
56
The `minimum` method's right hand side passes `descending` as an explicit argument to `maximum(xs)`.
34
-
But usually, explicit arguments for context parameters are be left out. For instance,
57
+
But usually, explicit arguments for inferable parameters are be left out. For instance,
35
58
given `xs: List[Int]`, the following calls are all possible (and they all normalize to the last one:)
36
59
```scala
37
-
maximum(xs)
60
+
minimum(xs)
38
61
maximum(xs) givendescending
39
-
maximum(xs) given (descending givenIntOrd)
62
+
maximum(xs) given (descending givenListOrd)
63
+
maximum(xs) given (descending given (ListOrdgivenInOrd))
40
64
```
41
-
Arguments for context parameters must use the `given` syntax. So the expression `maximum(xs)(descending)` would produce a type error.
65
+
In summary, the argument passed in the definition of minimum is constructed
66
+
from the `descending` function applied to the argument `ListOrd`, which is
67
+
in turn applied to the argument `IntOrd`.
42
68
43
-
The `given` connective is treated like an infix operator with the same precedence as other operators that start with a letter. The expression following a `given` may also be an argument list consisting of several implicit arguments separated by commas. If a tuple should be passed as a single implicit argument (probably an uncommon case), it has to be put in a pair of extra parentheses:
44
-
```scala
45
-
deffgiven (x: A, y: B)
46
-
f given (a, b)
69
+
## Mixing Inferable And Normal Parameters
47
70
48
-
defggiven (xy: (A, B))
49
-
g given ((a, b))
50
-
```
51
-
Unlike existing implicit parameters, context parameters can be freely mixed with normal parameter lists.
52
-
A context parameter may be followed by a normal parameter and _vice versa_. There can be several context parameter
53
-
lists in a definition. Example:
71
+
Inferable parameters can be freely mixed with normal parameter lists.
72
+
An inferable parameter may be followed by a normal parameter and _vice versa_.
73
+
There can be several inferable parameter lists in a definition. Example:
Context parameters may be given either as a normal parameter list `(...)`
68
-
or as a sequence of types. To distinguish the two, a leading `(` always indicates a parameter list.
69
87
70
-
## Summoning an Instance
88
+
## Summmoning an Inferred Instance
71
89
72
-
A method `summon` in `Predef` returns the inferred value for a given type, analogously to what `implicitly[T]` did. The only difference between the two is that
73
-
`summon` takes a context parameter, where `implicitly` took an old-style implicit parameter:
90
+
A method `infer` in `Predef` creates an instance value for a given type. For example,
91
+
the instance value for `Ord[List[Int]]` is generated by
92
+
```
93
+
infer[Ord[List[Int]]]
94
+
```
95
+
The `infer` method is simply defined as the identity function with an inferable parameter.
74
96
```scala
75
-
defsummon[T] with (x: T) = x
97
+
definfer[T] given (x: T) = x
76
98
```
77
99
78
100
## Syntax
@@ -82,7 +104,10 @@ Here is the new syntax of parameters and arguments seen as a delta from the [sta
0 commit comments