@@ -25,29 +25,31 @@ import org.scalatest.matchers.should.Matchers
25
25
import scala .util .{Success , Try }
26
26
27
27
/**
28
- * @param name handling_error_without_exceptions
28
+ * @param name
29
+ * handling_error_without_exceptions
29
30
*/
30
31
object ErrorHandlingSection
31
32
extends AnyFlatSpec
32
33
with Matchers
33
34
with org.scalaexercises.definitions.Section {
34
35
35
36
/**
36
- * = Functional programming in Scala =
37
+ * =Functional programming in Scala=
37
38
*
38
- * The following set of sections represent the exercises contained in the book "Functional Programming in Scala",
39
- * written by Paul Chiusano and Rúnar Bjarnason and published by Manning. This content library is meant to be used
40
- * in tandem with the book. We use the same numeration for the exercises for you to follow them.
39
+ * The following set of sections represent the exercises contained in the book "Functional
40
+ * Programming in Scala", written by Paul Chiusano and Rúnar Bjarnason and published by Manning.
41
+ * This content library is meant to be used in tandem with the book. We use the same numeration
42
+ * for the exercises for you to follow them.
41
43
*
42
- * For more information about "Functional Programming in Scala" please visit its
43
- * <a href="https://www.manning.com/books/functional-programming-in-scala">official website</a>.
44
+ * For more information about "Functional Programming in Scala" please visit its <a
45
+ * href="https://www.manning.com/books/functional-programming-in-scala">official website</a>.
44
46
*
45
- * = The Option data type =
47
+ * =The Option data type=
46
48
*
47
49
* <b>Exercise 4.1</b>:
48
50
*
49
- * We're going to look at some of the functions available in the `Option`, starting by `map`, that applies a function
50
- * `f` in the `Option` is not `None`:
51
+ * We're going to look at some of the functions available in the `Option`, starting by `map`, that
52
+ * applies a function `f` in the `Option` is not `None`:
51
53
*
52
54
* {{{
53
55
* def map[B](f: A => B): Option[B] = this match {
@@ -87,7 +89,8 @@ object ErrorHandlingSection
87
89
}
88
90
89
91
/**
90
- * We can also implement `flatMap`, which applies a function `f` which may also fail, to the `Option` if not `None`:
92
+ * We can also implement `flatMap`, which applies a function `f` which may also fail, to the
93
+ * `Option` if not `None`:
91
94
*
92
95
* {{{
93
96
* def flatMap[B](f: A => Option[B]): Option[B] = map(f) getOrElse None
@@ -104,8 +107,8 @@ object ErrorHandlingSection
104
107
}
105
108
106
109
/**
107
- * The function `getOrElse` tries to get the value contained in the Option, but if it's a `None`, it will
108
- * return the default value provided by the caller:
110
+ * The function `getOrElse` tries to get the value contained in the Option, but if it's a `None`,
111
+ * it will return the default value provided by the caller:
109
112
*
110
113
* {{{
111
114
* def getOrElse[B>:A](default: => B): B = this match {
@@ -114,8 +117,8 @@ object ErrorHandlingSection
114
117
* }
115
118
* }}}
116
119
*
117
- * `orElse` returns the original `Option` if not `None`, or returns the provided `Option` as an alternative in that
118
- * case:
120
+ * `orElse` returns the original `Option` if not `None`, or returns the provided `Option` as an
121
+ * alternative in that case:
119
122
*
120
123
* {{{
121
124
* def orElse[B>:A](ob: => Option[B]): Option[B] = this map (Some(_)) getOrElse ob
@@ -132,8 +135,8 @@ object ErrorHandlingSection
132
135
}
133
136
134
137
/**
135
- * Finally, we can implement a `filter` function that will turn any `Option` into a `None` if it doesn't satisfy the
136
- * provided predicate:
138
+ * Finally, we can implement a `filter` function that will turn any `Option` into a `None` if it
139
+ * doesn't satisfy the provided predicate:
137
140
*
138
141
* {{{
139
142
* def filter(f: A => Boolean): Option[A] = this match {
@@ -157,8 +160,8 @@ object ErrorHandlingSection
157
160
/**
158
161
* <b>Exercise 4.2:</b>
159
162
*
160
- * Let's implement the `variance` function in terms of `flatMap`. If the mean of a sequence is `m`, the variance
161
- * is the mean of `math.pow(x - m, 2)` for each element in the sequence:
163
+ * Let's implement the `variance` function in terms of `flatMap`. If the mean of a sequence is
164
+ * `m`, the variance is the mean of `math.pow(x - m, 2)` for each element in the sequence:
162
165
*
163
166
* {{{
164
167
* def variance(xs: Seq[Double]): Option[Double] =
@@ -167,8 +170,9 @@ object ErrorHandlingSection
167
170
*
168
171
* <b>Exercise 4.3:</b>
169
172
*
170
- * Let's write a generic function to combine two `Option` values , so that if any of those values is `None`, the
171
- * result value is too; and otherwise it will be the result of applying the provided function:
173
+ * Let's write a generic function to combine two `Option` values , so that if any of those values
174
+ * is `None`, the result value is too; and otherwise it will be the result of applying the
175
+ * provided function:
172
176
*
173
177
* {{{
174
178
* def map2[A,B,C](a: Option[A], b: Option[B])(f: (A, B) => C): Option[C] =
@@ -177,10 +181,10 @@ object ErrorHandlingSection
177
181
*
178
182
* <b>Exercise 4.4:</b>
179
183
*
180
- * Let's continue by looking at a few other similar cases. For instance, the `sequence` function, which combines a list
181
- * of `Option`s into another `Option` containing a list of all the `Some`s in the original one. If the original
182
- * list contains `None` at least once, the result of the function should be `None`. If not , the result should be a
183
- * `Some` with a list of all the values:
184
+ * Let's continue by looking at a few other similar cases. For instance, the `sequence` function,
185
+ * which combines a list of `Option`s into another `Option` containing a list of all the `Some`s
186
+ * in the original one. If the original list contains `None` at least once , the result of the
187
+ * function should be `None`. If not, the result should be a `Some` with a list of all the values:
184
188
*
185
189
* {{{
186
190
* def sequence(a: List[Option[A]]): Option[List[A]] = a match {
@@ -199,8 +203,9 @@ object ErrorHandlingSection
199
203
/**
200
204
* <b>Exercise 4.5:</b>
201
205
*
202
- * The last `Option` function we're going to explore is `traverse`, that will allow us to map over a list using a
203
- * function that might fail, returning `None` if applying it to any element of the list returns `None`:
206
+ * The last `Option` function we're going to explore is `traverse`, that will allow us to map over
207
+ * a list using a function that might fail, returning `None` if applying it to any element of the
208
+ * list returns `None`:
204
209
*
205
210
* {{{
206
211
* def traverse[A, B](a: List[A])(f: A => Option[B]): Option[List[B]] = a match {
@@ -239,12 +244,12 @@ object ErrorHandlingSection
239
244
}
240
245
241
246
/**
242
- * = The Either data type =
247
+ * =The Either data type=
243
248
*
244
249
* <b>Exercise 4.6:</b>
245
250
*
246
- * As we did with `Option`, let's implement versions of `map`, `flatMap`, `orElse` and `map2` on `Either` that
247
- * operate on the `Right` value, starting with `map`:
251
+ * As we did with `Option`, let's implement versions of `map`, `flatMap`, `orElse` and `map2` on
252
+ * `Either` that operate on the `Right` value, starting with `map`:
248
253
*
249
254
* {{{
250
255
* def map[B](f: A => B): Either[E, B] = this match {
@@ -253,10 +258,11 @@ object ErrorHandlingSection
253
258
* }
254
259
* }}}
255
260
*
256
- * In the same fashion as `Option`, `map` allows us to chain operations on an `Either` without worrying about the
257
- * possible errors that may arise, as the chain will stop if any error occurs. Let's try it out, by improving the
258
- * employee lookup function we implemented before, to use `Either` instead of `Option`. Try to use `map` on the
259
- * `Either` type to obtain the department of each employee:
261
+ * In the same fashion as `Option`, `map` allows us to chain operations on an `Either` without
262
+ * worrying about the possible errors that may arise, as the chain will stop if any error occurs.
263
+ * Let's try it out, by improving the employee lookup function we implemented before, to use
264
+ * `Either` instead of `Option`. Try to use `map` on the `Either` type to obtain the department of
265
+ * each employee:
260
266
*/
261
267
def eitherMapAssert (res0 : (Either [String , Employee ]) => Either [String , String ]): Unit = {
262
268
def lookupByNameViaEither (name : String ): Either [String , Employee ] =
@@ -275,9 +281,9 @@ object ErrorHandlingSection
275
281
}
276
282
277
283
/**
278
- * `flatMap` behaves the same in `Either` as it does in `Option`, allowing us to chain operations that may also fail.
279
- * Use it to try to obtain the managers from each employee. Note that when calling our `getManager` function, we can
280
- * find two different errors in its execution:
284
+ * `flatMap` behaves the same in `Either` as it does in `Option`, allowing us to chain operations
285
+ * that may also fail. Use it to try to obtain the managers from each employee. Note that when
286
+ * calling our `getManager` function, we can find two different errors in its execution:
281
287
*/
282
288
def eitherFlatMapAssert (res0 : Right [String ], res1 : Left [String ], res2 : Left [String ]): Unit = {
283
289
def getManager (employee : Either [String , Employee ]): Either [String , String ] =
@@ -294,8 +300,8 @@ object ErrorHandlingSection
294
300
}
295
301
296
302
/**
297
- * `orElse` works the same as in `Option`s, returning the original `Either` when it contains a `Right`, or the
298
- * provided alternative in case it's a `Left`:
303
+ * `orElse` works the same as in `Option`s, returning the original `Either` when it contains a
304
+ * `Right`, or the provided alternative in case it's a `Left`:
299
305
*
300
306
* {{{
301
307
* def orElse[EE >: E, AA >: A](b: => Either[EE, AA]): Either[EE, AA] = this match {
@@ -304,8 +310,8 @@ object ErrorHandlingSection
304
310
* }
305
311
* }}}
306
312
*
307
- * Let's check out how it behaves. Let's assume that everyone inside our company ends up responding to a "Mr. CEO"
308
- * manager. We can provide that logic with `orElse`:
313
+ * Let's check out how it behaves. Let's assume that everyone inside our company ends up
314
+ * responding to a "Mr. CEO" manager. We can provide that logic with `orElse`:
309
315
*/
310
316
def eitherOrElseAssert (res0 : Right [String ], res1 : Right [String ], res2 : Right [String ]): Unit = {
311
317
def getManager (employee : Either [String , Employee ]): Either [String , String ] =
@@ -322,8 +328,9 @@ object ErrorHandlingSection
322
328
}
323
329
324
330
/**
325
- * In the same fashion as with `Option`s, `map2` lets us combine two `Either`s using a binary function. Note that we
326
- * will use for-comprehensions instead of a chain of `flatMap` and `map` calls:
331
+ * In the same fashion as with `Option`s, `map2` lets us combine two `Either`s using a binary
332
+ * function. Note that we will use for-comprehensions instead of a chain of `flatMap` and `map`
333
+ * calls:
327
334
*
328
335
* {{{
329
336
* def map2[EE >: E, B, C](b: Either[EE, B])(f: (A, B) => C): Either[EE, C] =
@@ -333,8 +340,8 @@ object ErrorHandlingSection
333
340
* } yield f(a,b1)
334
341
* }}}
335
342
*
336
- * In this implementation, we can't report errors on both sides. To do that, we would need a new data type that can
337
- * hold a list of errors:
343
+ * In this implementation, we can't report errors on both sides. To do that, we would need a new
344
+ * data type that can hold a list of errors:
338
345
*
339
346
* {{{
340
347
* trait Partial[+A,+B]
@@ -344,8 +351,8 @@ object ErrorHandlingSection
344
351
*
345
352
* This data type is really similar to Scalaz' `Validation` type.
346
353
*
347
- * In any case, let's test `map2` on the following exercise, to find out if two employees share a department by using
348
- * an specific function:
354
+ * In any case, let's test `map2` on the following exercise, to find out if two employees share a
355
+ * department by using an specific function:
349
356
*/
350
357
def eitherMap2Assert (res0 : Right [Boolean ], res1 : Right [Boolean ], res2 : Left [String ]): Unit = {
351
358
def employeesShareDepartment (employeeA : Employee , employeeB : Employee ) =
@@ -365,8 +372,8 @@ object ErrorHandlingSection
365
372
/**
366
373
* <b>Exercise 4.7:</b>
367
374
*
368
- * `sequence` and `traverse` can also be implemented for `Either`. Those functions should return the first error that
369
- * can be found, if there is one.
375
+ * `sequence` and `traverse` can also be implemented for `Either`. Those functions should return
376
+ * the first error that can be found, if there is one.
370
377
*
371
378
* {{{
372
379
* def traverse[E,A,B](es: List[A])(f: A => Either[E, B]): Either[E, List[B]] = es match {
@@ -390,8 +397,8 @@ object ErrorHandlingSection
390
397
}
391
398
392
399
/**
393
- * As for `sequence`, we can create a `List` of the employees we looked up by using the `lookupByNameViaEither`, and
394
- * find out if we were looking for a missing person:
400
+ * As for `sequence`, we can create a `List` of the employees we looked up by using the
401
+ * `lookupByNameViaEither`, and find out if we were looking for a missing person:
395
402
*/
396
403
def eitherSequenceAssert (res0 : Right [List [Employee ]], res1 : Left [String ]): Unit = {
397
404
val employees = List (lookupByNameViaEither(" Joe" ), lookupByNameViaEither(" Mary" ))
0 commit comments