Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
fpinscala/exercises/src/main/scala/fpinscala/errorhandling/Option.scala
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
80 lines (66 sloc)
2.43 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package fpinscala.errorhandling | |
// hide std library `Option`, `Some` and `Either`, since we are writing our | |
// own in this chapter | |
import scala.{Option => _, Some => _, Either => _, _} | |
sealed trait Option[+A] { | |
def map[B](f: A => B): Option[B] = this match { | |
case None => None | |
case Some(x) => Some(f(x)) | |
} | |
def getOrElse[B>:A](default: => B): B = this match { | |
case None => default | |
case Some(x) => x | |
} | |
def flatMap[B](f: A => Option[B]): Option[B] = map(f) getOrElse None | |
def orElse[B>:A](ob: => Option[B]): Option[B] = | |
this map (Some(_)) getOrElse ob | |
def filter(f: A => Boolean): Option[A] = this match { | |
case Some(x) if f(x) => this | |
case _ => 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 = ...` declares `y` as having type `Int`, and sets it | |
// equal to the right hand side of the `=`. | |
val y: Int = throw new Exception("fail!") | |
try { | |
val x = 42 + 5 | |
x + y | |
} | |
// 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. | |
catch { case e: Exception => 43 } | |
} | |
def failingFn2(i: Int): Int = { | |
try { | |
val x = 42 + 5 | |
// A thrown Exception can be given any type; here we're annotating | |
// it with the type `Int` | |
x + ((throw new Exception("fail!")): 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(x - m, 2)))) | |
// def map2[A,B,C](a: Option[A], b: Option[B])(f: (A, B) => C): Option[C] = | |
// (a, b) match { | |
// case (_, None) => None | |
// case (None, _) => None | |
// case (Some(x), Some(y)) => Some(f(x, y)) | |
// } | |
// Exercise 4.3 -- using hint | |
def map2[A,B,C](a: Option[A], b: Option[B])(f: (A, B) => C): Option[C] = | |
a flatMap (a1 => b map (b1 => f(a1, b1))) | |
def sequence[A](a: List[Option[A]]): Option[List[A]] = | |
a.foldRight[Option[List[A]]](Some(Nil))((h, t) => map2(h, t)(_ :: _)) | |
def traverse[A, B](a: List[A])(f: A => Option[B]): Option[List[B]] = | |
a.foldRight[Option[List[B]]](Some(Nil))((h, t) => map2(f(h), t)(_ :: _)) | |
} |