-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathOption.scala
76 lines (61 loc) · 2.37 KB
/
Option.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package fpinscala.errorhandling
import scala.{Option => _, Some => _, Either => _, _} // hide std library `Option`, `Some` and `Either`, since we are writing our own in this chapter
sealed trait Option[+A] {
def map[B](f: A => B): Option[B] = this match {
case Some(a) => Some(f(a))
case None => None
}
def getOrElse[B>:A](default: => B): B = this match {
case Some(a) => a
case None => default
}
def flatMap[B](f: A => Option[B]): Option[B] =
map(f).getOrElse(None)
def orElse[B>:A](ob: => Option[B]): Option[B] =
map (Some(_)) getOrElse ob
def filter(f: A => Boolean): Option[A] =
flatMap { a => if (f(a)) Some(a) else None }
}
case class Some[+A](get: A) extends Option[A]
case object None extends Option[Nothing]
object Option {
def failingFn(i: Int): Int = {
val y: Int = throw new Exception("fail!") // `val y: Int = ...` declares `y` as having type `Int`, and sets it equal to the right hand side of the `=`.
try {
val x = 42 + 5
x + y
}
catch { case e: Exception => 43 } // A `catch` block is just a pattern matching block like the ones we've seen. `case e: Exception` is a pattern that matches any `Exception`, and it binds this value to the identifier `e`. The match returns the value 43.
}
def failingFn2(i: Int): Int = {
try {
val x = 42 + 5
x + ((throw new Exception("fail!")): Int) // A thrown Exception can be given any type; here we're annotating it with the type `Int`
}
catch { case e: Exception => 43 }
}
def mean(xs: Seq[Double]): Option[Double] =
if (xs.isEmpty) None
else Some(xs.sum / xs.length)
def variance(xs: Seq[Double]): Option[Double] = {
mean(xs) flatMap { m =>
mean(xs map(x => math.pow(m - x, 2)))
}
}
def map2[A,B,C](oa: Option[A], ob: Option[B])(f: (A, B) => C): Option[C] =
// oa flatMap { a => ob map {b => f(a,b) } }
for {
a <- oa
b <- ob
} yield f(a,b)
def sequence[A](as: List[Option[A]]): Option[List[A]] = as match {
case Nil => Some(Nil)
case h :: t => h flatMap (a => sequence(t) map (a :: _))
}
// def sequence_1[A](a: List[Option[A]]): Option[List[A]] =
// a.foldRight[Option[List[A]]](Some(Nil))((x,y) => map2(x,y)(_ :: _))
def traverse[A, B](a: List[A])(f: A => Option[B]): Option[List[B]] = a match {
case Nil => Some(Nil)
case h :: t => map2(f(h), traverse(t)(f))(_ :: _)
}
}