Skip to content

Commit e901185

Browse files
authored
Merge pull request #2530 from flomebul/multiple-parameter-lists
Add code tabs for _tour/multiple-parameter-lists.md
2 parents 2f94b00 + 308327c commit e901185

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed

_tour/multiple-parameter-lists.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,44 @@ Methods may have multiple parameter lists.
1616

1717
Here is an example, as defined on the `Iterable` trait in Scala's collections API:
1818

19+
{% tabs foldLeft_definition class=tabs-scala-version %}
20+
21+
{% tab 'Scala 2' for=foldLeft_definition %}
1922
```scala
2023
trait Iterable[A] {
2124
...
2225
def foldLeft[B](z: B)(op: (B, A) => B): B
2326
...
2427
}
2528
```
29+
{% endtab %}
30+
31+
{% tab 'Scala 3' for=foldLeft_definition %}
32+
```scala
33+
trait Iterable[A]:
34+
...
35+
def foldLeft[B](z: B)(op: (B, A) => B): B
36+
...
37+
```
38+
{% endtab %}
39+
40+
{% endtabs %}
2641

2742
`foldLeft` applies a two-parameter function `op` to an initial value `z` and all elements of this collection, going left to right. Shown below is an example of its usage.
2843

2944
Starting with an initial value of 0, `foldLeft` here applies the function `(m, n) => m + n` to each element in the List and the previous accumulated value.
3045

46+
{% tabs foldLeft_use %}
47+
48+
{% tab 'Scala 2 and 3' for=foldLeft_use %}
3149
```scala mdoc
3250
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
3351
val res = numbers.foldLeft(0)((m, n) => m + n)
3452
println(res) // 55
3553
```
54+
{% endtab %}
55+
56+
{% endtabs %}
3657

3758
### Use cases
3859

@@ -43,29 +64,53 @@ Suggested use cases for multiple parameter lists include:
4364
It so happens that in Scala, type inference proceeds one parameter list at a time.
4465
Say you have the following method:
4566

67+
{% tabs foldLeft1_definition %}
68+
69+
{% tab 'Scala 2 and 3' for=foldLeft1_definition %}
4670
```scala mdoc
4771
def foldLeft1[A, B](as: List[A], b0: B, op: (B, A) => B) = ???
4872
```
73+
{% endtab %}
74+
75+
{% endtabs %}
4976

5077
Then you'd like to call it in the following way, but will find that it doesn't compile:
5178

79+
{% tabs foldLeft1_wrong_use %}
80+
81+
{% tab 'Scala 2 and 3' for=foldLeft1_wrong_use %}
5282
```scala mdoc:fail
5383
def notPossible = foldLeft1(numbers, 0, _ + _)
5484
```
85+
{% endtab %}
86+
87+
{% endtabs %}
5588

5689
you will have to call it like one of the below ways:
5790

91+
{% tabs foldLeft1_good_use %}
92+
93+
{% tab 'Scala 2 and 3' for=foldLeft1_good_use %}
5894
```scala mdoc
5995
def firstWay = foldLeft1[Int, Int](numbers, 0, _ + _)
6096
def secondWay = foldLeft1(numbers, 0, (a: Int, b: Int) => a + b)
6197
```
98+
{% endtab %}
99+
100+
{% endtabs %}
62101

63102
That's because Scala won't be able to infer the type of the function `_ + _`, as it's still inferring `A` and `B`. By moving the parameter `op` to its own parameter list, `A` and `B` are inferred in the first parameter list. These inferred types will then be available to the second parameter list and `_ + _` will match the inferred type `(Int, Int) => Int`
64103

104+
{% tabs foldLeft2_definition_and_use %}
105+
106+
{% tab 'Scala 2 and 3' for=foldLeft2_definition_and_use %}
65107
```scala mdoc
66108
def foldLeft2[A, B](as: List[A], b0: B)(op: (B, A) => B) = ???
67109
def possible = foldLeft2(numbers, 0)(_ + _)
68110
```
111+
{% endtab %}
112+
113+
{% endtabs %}
69114

70115
This definition doesn't need any type hints and can infer all of its type parameters.
71116

@@ -76,16 +121,31 @@ To specify only certain parameters as [`implicit`](https://docs.scala-lang.org/t
76121

77122
An example of this is:
78123

124+
{% tabs execute_definition class=tabs-scala-version %}
125+
126+
{% tab 'Scala 2' for=execute_definition %}
79127
```scala mdoc
80128
def execute(arg: Int)(implicit ec: scala.concurrent.ExecutionContext) = ???
81129
```
130+
{% endtab %}
131+
132+
{% tab 'Scala 3' for=execute_definition %}
133+
```scala
134+
def execute(arg: Int)(using ec: scala.concurrent.ExecutionContext) = ???
135+
```
136+
{% endtab %}
137+
138+
{% endtabs %}
82139

83140
#### Partial application
84141

85142
When a method is called with a fewer number of parameter lists, then this will yield a function taking the missing parameter lists as its arguments. This is formally known as [partial application](https://en.wikipedia.org/wiki/Partial_application).
86143

87144
For example,
88145

146+
{% tabs foldLeft_partial %}
147+
148+
{% tab 'Scala 2 and 3' for=foldLeft_partial %}
89149
```scala mdoc:nest
90150
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
91151
val numberFunc = numbers.foldLeft(List[Int]()) _
@@ -96,6 +156,9 @@ println(squares) // List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)
96156
val cubes = numberFunc((xs, x) => xs :+ x*x*x)
97157
println(cubes) // List(1, 8, 27, 64, 125, 216, 343, 512, 729, 1000)
98158
```
159+
{% endtab %}
160+
161+
{% endtabs %}
99162

100163
### Comparison with "currying"
101164

@@ -122,6 +185,9 @@ multiple parameter lists and currying. Though they are different at
122185
the definition site, the call site might nonetheless look identical,
123186
as in this example:
124187

188+
{% tabs about_currying %}
189+
190+
{% tab 'Scala 2 and 3' for=about_currying %}
125191
```scala mdoc
126192
// version with multiple parameter lists
127193
def addMultiple(n1: Int)(n2: Int) = n1 + n2
@@ -134,3 +200,6 @@ addMultiple(3)(4) // 7
134200
addCurried1(3)(4) // 7
135201
addCurried2(3)(4) // 7
136202
```
203+
{% endtab %}
204+
205+
{% endtabs %}

0 commit comments

Comments
 (0)