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
Copy file name to clipboardExpand all lines: _overviews/scala3-book/fun-hofs.md
+28-17
Original file line number
Diff line number
Diff line change
@@ -15,8 +15,6 @@ In Scala, HOFs are possible because functions are first-class values.
15
15
As an important note, while we use the common industry term “higher-order function” in this document, in Scala this phrase applies to both *methods* and *functions*.
16
16
Thanks to Scala’s [Eta Expansion technology][eta_expansion], they can generally be used in the same places.
17
17
18
-
19
-
20
18
## From consumer to creator
21
19
22
20
In the examples so far in this book you’ve seen how to be a *consumer* of methods that take other functions as input parameters, such as using HOFs like `map` and `filter`.
@@ -32,8 +30,6 @@ In the process you’ll see:
32
30
33
31
As a beneficial side effect of this discussion, once you’re comfortable with this syntax, you’ll use it to define function parameters, anonymous functions, and function variables, and it also becomes easier to read the Scaladoc for higher-order functions.
34
32
35
-
36
-
37
33
## Understanding filter’s Scaladoc
38
34
39
35
To understand how higher-order functions work, it helps to dig into an example.
@@ -56,21 +52,27 @@ At this point, if you don’t know the purpose of the `filter` method, all you
56
52
57
53
Looking specifically at the function parameter `p`, this part of `filter`’s description:
58
54
55
+
{% tabs filter-definition_1 %}
56
+
{% tab 'Scala 2 and 3' %}
59
57
```scala
60
58
p:A=>Boolean
61
59
```
60
+
{% endtab %}
61
+
{% endtabs %}
62
62
63
63
means that whatever function you pass in must take the type `A` as an input parameter and return a `Boolean`.
64
64
So if your list is a `List[Int]`, you can replace the generic type `A` with `Int`, and read that signature like this:
65
65
66
+
{% tabs filter-definition_2 %}
67
+
{% tab 'Scala 2 and 3' %}
66
68
```scala
67
69
p:Int=>Boolean
68
70
```
71
+
{% endtab %}
72
+
{% endtabs %}
69
73
70
74
Because `isEven` has this type---it transforms an input `Int` into a resulting `Boolean`---it can be used with `filter`.
71
75
72
-
73
-
74
76
{% comment %}
75
77
NOTE: (A low-priority issue): The next several sections can be condensed.
This portion of the code---the *type signature*---states that `f` is a function, and defines the types of functions the `sayHello` method will accept:
103
105
106
+
{% tabs sayHello-definition_1 %}
107
+
{% tab 'Scala 2 and 3' %}
104
108
```scala
105
109
f: () =>Unit
106
110
```
111
+
{% endtab %}
112
+
{% endtabs %}
107
113
108
114
Here’s how this works:
109
115
@@ -125,7 +131,6 @@ def helloJoe(): Unit = println("Hello, Joe")
125
131
{% endtab %}
126
132
{% endtabs %}
127
133
128
-
129
134
Because the type signatures match, you can pass `helloJoe` into `sayHello`:
130
135
131
136
{% tabs sayHello-usage %}
@@ -139,7 +144,6 @@ sayHello(helloJoe) // prints "Hello, Joe"
139
144
If you’ve never done this before, congratulations:
140
145
You just defined a method named `sayHello` that takes a function as an input parameter, and then invokes that function in its method body.
141
146
142
-
143
147
### sayHello can take many functions
144
148
145
149
It’s important to know that the beauty of this approach is not that `sayHello` can take *one* function as an input parameter; the beauty is that it can take *any* function that matches `f`’s signature.
@@ -167,8 +171,6 @@ Bonjour, Julien
167
171
This is a good start.
168
172
The only thing to do now is see a few more examples of how to define different type signatures for function parameters.
169
173
170
-
171
-
172
174
## The general syntax for defining function input parameters
173
175
174
176
In this method:
@@ -183,26 +185,38 @@ def sayHello(f: () => Unit): Unit
183
185
184
186
We noted that the type signature for `f` is:
185
187
188
+
{% tabs sayHello-definition-2_1 %}
189
+
{% tab 'Scala 2 and 3' %}
186
190
```scala
187
191
() =>Unit
188
192
```
193
+
{% endtab %}
194
+
{% endtabs %}
189
195
190
196
We know that this means, “a function that takes no input parameters and returns nothing meaningful (given by `Unit`).”
191
197
192
198
To demonstrate more type signature examples, here’s a function that takes a `String` parameter and returns an `Int`:
193
199
200
+
{% tabs sayHello-definition-2_2 %}
201
+
{% tab 'Scala 2 and 3' %}
194
202
```scala
195
203
f:String=>Int
196
204
```
205
+
{% endtab %}
206
+
{% endtabs %}
197
207
198
208
What kinds of functions take a string and return an integer?
199
209
Functions like “string length” and checksum are two examples.
200
210
201
211
Similarly, this function takes two `Int` parameters and returns an `Int`:
202
212
213
+
{% tabs sayHello-definition-2_3 %}
214
+
{% tab 'Scala 2 and 3' %}
203
215
```scala
204
216
f: (Int, Int) =>Int
205
217
```
218
+
{% endtab %}
219
+
{% endtabs %}
206
220
207
221
Can you imagine what sort of functions match that signature?
208
222
@@ -220,15 +234,17 @@ def multiply(a: Int, b: Int): Int = a * b
220
234
221
235
As you can infer from these examples, the general syntax for defining function parameter type signatures is:
222
236
237
+
{% tabs add-sub-mul-definitions_1 %}
238
+
{% tab 'Scala 2 and 3' %}
223
239
```scala
224
240
variableName: (parameterTypes ...) => returnType
225
241
```
242
+
{% endtab %}
243
+
{% endtabs %}
226
244
227
245
> Because functional programming is like creating and combining a series of algebraic equations, it’s common to think about types a *lot* when designing functions and applications.
228
246
> You might say that you “think in types.”
229
247
230
-
231
-
232
248
## Taking a function parameter along with other parameters
233
249
234
250
For HOFs to be really useful, they also need some data to work on.
@@ -279,11 +295,8 @@ Hello, world
279
295
{% endtab %}
280
296
{% endtabs %}
281
297
282
-
283
298
Excellent.
284
299
The `executeNTimes` method executes the `helloWorld` function three times.
285
-
286
-
287
300
### As many parameters as needed
288
301
289
302
Your methods can continue to get as complicated as necessary.
Because these `sum` and `multiply` methods match that type signature, they can be passed into `executeAndPrint` along with two `Int` values:
303
315
304
316
{% tabs executeAndPrint-usage %}
@@ -313,7 +325,6 @@ executeAndPrint(multiply, 3, 9) // prints 27
313
325
{% endtab %}
314
326
{% endtabs %}
315
327
316
-
317
328
## Function type signature consistency
318
329
319
330
A great thing about learning about Scala’s function type signatures is that the syntax you use to define function input parameters is the same syntax you use to write function literals.
0 commit comments