Skip to content

Commit 3f88e4a

Browse files
Javier de Silóniz Sandinoraulraja
Javier de Silóniz Sandino
authored andcommitted
Removed excerpts of text from the sections (#19)
1 parent 5a04144 commit 3f88e4a

11 files changed

+259
-1226
lines changed

src/main/scala/fpinscalalib/ErrorHandlingSection.scala

Lines changed: 29 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -15,50 +15,17 @@ object ErrorHandlingSection extends FlatSpec with Matchers with org.scalaexercis
1515
*
1616
* The following set of sections represent the exercises contained in the book "Functional Programming in Scala",
1717
* written by Paul Chiusano and Rúnar Bjarnason and published by Manning. This content library is meant to be used
18-
* in tandem with the book, although excerpts of the theory needed to complete them have been added to guide you.
18+
* in tandem with the book. We use the same numeration for the exercises for you to follow them.
1919
*
2020
* For more information about "Functional Programming in Scala" please visit its
2121
* <a href="https://www.manning.com/books/functional-programming-in-scala">official website</a>.
2222
*
2323
* = The Option data type =
2424
*
25-
* Exceptions break referential transparency and introduce context dependence. Moreover, they are not type-safe,
26-
* hiding information about the fact that they may occur, to the developer and the compiler. We're going to explore
27-
* an alternative to exceptions without these drawbacks, without losing out on the primary benefit of exceptions:
28-
* they allow us to `consolidate and centralize error-handling logic`. The technique we use is based on an old idea:
29-
* instead of throwing an exception, we return a value indicating that an exceptional condition has occurred. instead
30-
* of using error codes, we introduce a new generic type for these “possibly defined values” and use higher-order
31-
* functions to encapsulate common patterns of handling and propagating errors.
25+
* <b>Exercise 4.1</b>:
3226
*
33-
* We're going to introduce a new type, `Option`. As with the previously explored `List`, this type also exists in
34-
* the Scala standard library, but we're re-creating it here for pedagogical purposes:
35-
*
36-
* {{{
37-
* sealed trait Option[+A]
38-
* case class Some[+A](get: A) extends Option[A]
39-
* case object None extends Option[Nothing]
40-
* }}}
41-
*
42-
* Option has two cases: it can be defined, in which case it will be a `Some`, or it can be undefined, in which case
43-
* it will be `None`.
44-
*
45-
* Let's consider an example on how we can use our new type. We're defining a function `mean` that computes the mean
46-
* of a list, which is undefined if the list is empty:
47-
*/
48-
49-
def optionMeanAssert(res0: Option[Double]): Unit = {
50-
def mean(xs: Seq[Double]): Option[Double] =
51-
if (xs.isEmpty) None
52-
else Some(xs.sum / xs.length)
53-
54-
mean(Seq(1, 2, 3, 4, 5)) shouldBe Some(3.0)
55-
mean(Seq.empty) shouldBe res0
56-
}
57-
58-
/**
59-
* `Option` can be thought of like a `List` that can contain at most one element, and many of the `List` functions we
60-
* saw earlier have analogous functions on `Option`. We're going to look at some of these functions, starting by `map`,
61-
* that applies a function `f` in the `Option` is not `None`:
27+
* We're going to look at some of the functions available in the `Option`, starting by `map`, that applies a function
28+
* `f` in the `Option` is not `None`:
6229
*
6330
* {{{
6431
* def map[B](f: A => B): Option[B] = this match {
@@ -98,8 +65,7 @@ object ErrorHandlingSection extends FlatSpec with Matchers with org.scalaexercis
9865
* def flatMap[B](f: A => Option[B]): Option[B] = map(f) getOrElse None
9966
* }}}
10067
*
101-
* By using `flatMap` we can chain operations that can also fail, as in the following example. Try to find out who is
102-
* managing each employee, if applicable:
68+
* Try to find out who is managing each employee, if applicable:
10369
*/
10470

10571
def optionFlatMapAssert(res0: (Option[Employee]) => Option[String]): Unit = {
@@ -111,10 +77,8 @@ object ErrorHandlingSection extends FlatSpec with Matchers with org.scalaexercis
11177
}
11278

11379
/**
114-
* The function `getOrElse` used above, tries to get the value contained in the Option, but if it's a `None`, it will
115-
* return the default value provided by the caller. The `B >: A` in the declaration tells that the `B` type parameter
116-
* must be a supertype of `A`. Furthermore, `default : => B` indicates that the argument is of type B, but won’t be
117-
* evaluated until it’s needed by the function.
80+
* The function `getOrElse` tries to get the value contained in the Option, but if it's a `None`, it will
81+
* return the default value provided by the caller:
11882
*
11983
* {{{
12084
* def getOrElse[B>:A](default: => B): B = this match {
@@ -129,6 +93,8 @@ object ErrorHandlingSection extends FlatSpec with Matchers with org.scalaexercis
12993
* {{{
13094
* def orElse[B>:A](ob: => Option[B]): Option[B] = this map (Some(_)) getOrElse ob
13195
* }}}
96+
*
97+
* Check how it works in the following exercise:
13298
*/
13399

134100
def optionOrElseAssert(res0: Some[String], res1: Some[String], res2: Some[String]): Unit = {
@@ -139,7 +105,8 @@ object ErrorHandlingSection extends FlatSpec with Matchers with org.scalaexercis
139105
getManager(lookupByName("Foo")).orElse(Some("Mr. CEO")) shouldBe res2
140106
}
141107

142-
/** Finally, we can implement a `filter` function that will turn any `Option` into a `None` if it doesn't satisfy the
108+
/**
109+
* Finally, we can implement a `filter` function that will turn any `Option` into a `None` if it doesn't satisfy the
143110
* provided predicate:
144111
*
145112
* {{{
@@ -159,6 +126,8 @@ object ErrorHandlingSection extends FlatSpec with Matchers with org.scalaexercis
159126
}
160127

161128
/**
129+
* <b>Exercise 4.2:</b>
130+
*
162131
* Let's implement the `variance` function in terms of `flatMap`. If the mean of a sequence is `m`, the variance
163132
* is the mean of `math.pow(x - m, 2)` for each element in the sequence:
164133
*
@@ -169,39 +138,22 @@ object ErrorHandlingSection extends FlatSpec with Matchers with org.scalaexercis
169138
*/
170139

171140
/**
172-
* We may find in some situations when we need to combine two `Option` values using a binary function, so that if any
173-
* of those values is `None`, the result value is too; and otherwise it will be the result of applying the provided
174-
* function. We'll call this function `map2`, take a look at its implementation:
141+
* <b>Exercise 4.3:</b>
142+
*
143+
* Let's write a generic function to combine two `Option` values , so that if any of those values is `None`, the
144+
* result value is too; and otherwise it will be the result of applying the provided function:
175145
*
176146
* {{{
177147
* def map2[A,B,C](a: Option[A], b: Option[B])(f: (A, B) => C): Option[C] =
178148
* a flatMap (aa => b map (bb => f(aa, bb)))
179149
* }}}
180150
*
181-
* Let's see an example of its use. Let's write a function `parseInsuranceRateQuote` which takes the age and a number
182-
* of speeding tickets as strings, and attempts to call another function called `insuranceRateQuote` if parsing both
183-
* values is valid:
184-
*
185-
* {{{
186-
* def Try[A](a: => A): Option[A] =
187-
* try Some(a)
188-
* catch { case e: Exception => None }
189-
*
190-
* def parseInsuranceRateQuote( age: String, numberOfSpeedingTickets: String): Option[Double] = {
191-
* val optAge: Option[Int] = Try { age.toInt }
192-
* val optTickets: Option[Int] = Try { numberOfSpeedingTickets.toInt } map2(optAge, optTickes)(insuranceRateQuote)
193-
* }
194-
* }}}
151+
* <b>Exercise 4.4:</b>
195152
*
196-
* As `Try` will return an `Option` containing the value of the operation it encapsulates (or a `None` if it returns
197-
* an exception), to combine both values we need to make use of the new `map2` function we just implemented.
198-
*/
199-
200-
/**
201153
* Let's continue by looking at a few other similar cases. For instance, the `sequence` function, which combines a list
202-
* of `Option`s into one `Option` containing a list of all the `Some` values in the original list. If the original
203-
* list contains `None` even once, the result of the function should be `None`. Otherwise the result should be a `Some`
204-
* with a list of all the values:
154+
* of `Option`s into another `Option` containing a list of all the `Some`s in the original one. If the original
155+
* list contains `None` at least once, the result of the function should be `None`. If not, the result should be a
156+
* `Some` with a list of all the values:
205157
*
206158
* {{{
207159
* def sequence(a: List[Option[A]]): Option[List[A]] = a match {
@@ -219,10 +171,10 @@ object ErrorHandlingSection extends FlatSpec with Matchers with org.scalaexercis
219171
}
220172

221173
/**
174+
* <b>Exercise 4.5:</b>
175+
*
222176
* The last `Option` function we're going to explore is `traverse`, that will allow us to map over a list using a
223-
* function that might fail, returning `None` if applying it to any element of the list returns `None`. Note that we
224-
* want to avoid traversing the list twice (first to apply the provided function to each element, and another to
225-
* combine these `Option` values into an optional `List`:
177+
* function that might fail, returning `None` if applying it to any element of the list returns `None`:
226178
*
227179
* {{{
228180
* def traverse[A, B](a: List[A])(f: A => Option[B]): Option[List[B]] = a match {
@@ -263,39 +215,8 @@ object ErrorHandlingSection extends FlatSpec with Matchers with org.scalaexercis
263215
/**
264216
* = The Either data type =
265217
*
266-
* One thing you may have noticed with `Option` is that it doesn’t tell us anything about what went wrong in the case
267-
* of an exceptional condition. All it can do is give us `None`, indicating that there’s no value to be had. But
268-
* sometimes we want to know more. For example, we might want a `String` that gives more information, or if an
269-
* exception was raised, we might want to know what that error actually was.
270-
*
271-
* In this section, we’ll walk through a simple extension to `Option`, the `Either` data type, which lets us track a
272-
* reason for the failure. Let’s look at its definition:
273-
*
274-
* {{{
275-
* sealed trait Either[+E, +A]
276-
* case class Left[+E](value: E) extends Either[E, Nothing]
277-
* case class Right[+A](value: A) extends Either[Nothing, A]
278-
* }}}
279-
*
280-
* `Either` only has two cases, just like `Option`. The essential difference is that both cases carry a value. When
281-
* we use it to indicate success or failure, by convention the `Right` constructor is reserved for the success case
282-
* (a pun on “right,” meaning correct), and `Left` is used for failure.
218+
* <b>Exercise 4.6:</b>
283219
*
284-
* Let's look at the `mean` example again, this time returning a `String` in case of failure:
285-
*/
286-
287-
def eitherMeanAssert(res0: Right[Double], res1: Left[String]): Unit = {
288-
def mean(xs: IndexedSeq[Double]): Either[String, Double] =
289-
if (xs.isEmpty)
290-
Left("mean of empty list!")
291-
else
292-
Right(xs.sum / xs.length)
293-
294-
mean(IndexedSeq(1.0, 2.0, 3.0, 4.0, 5.0)) shouldBe res0
295-
mean(IndexedSeq.empty) shouldBe res1
296-
}
297-
298-
/**
299220
* As we did with `Option`, let's implement versions of `map`, `flatMap`, `orElse` and `map2` on `Either` that
300221
* operate on the `Right` value, starting with `map`:
301222
*
@@ -409,8 +330,10 @@ object ErrorHandlingSection extends FlatSpec with Matchers with org.scalaexercis
409330
}
410331

411332
/**
412-
* `sequence` and `traverse` can also be implemented for `Either`. These should return the first error that's
413-
* encountered, if there is one.
333+
* <b>Exercise 4.7:</b>
334+
*
335+
* `sequence` and `traverse` can also be implemented for `Either`. Those functions should return the first error that
336+
* can be found, if there is one.
414337
*
415338
* {{{
416339
* def traverse[E,A,B](es: List[A])(f: A => Either[E, B]): Either[E, List[B]] = es match {

0 commit comments

Comments
 (0)