Skip to content

Commit

Permalink
chapter 4 up to 4.5
Browse files Browse the repository at this point in the history
  • Loading branch information
dr0pi committed Apr 17, 2016
1 parent ad32171 commit b2afb64
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 33 deletions.
69 changes: 60 additions & 9 deletions Chapter4Worksheet.sc
Original file line number Diff line number Diff line change
@@ -1,21 +1,72 @@
import scala.{Option => _, _}

case class Some[+A](get: A) extends Option[A]
case object None extends Option[Nothing] {
def get = throw new Exception("nothing to see here")
}

trait Option[+A] {
def get: A

def map[B](f: A => B): Option[B] = this match {
case Some(_) => Some(f(this.get))
case None => None
}
def flatMap[B](f: A => Option[B]): Option[B] = ???
def getOrElse[B >: A](default: => B): B = ???
def orElse[B >: A](ob: => Option[B]): Option[B] = ???
def filter(f: A => Boolean): Option[A] = ???
}
case class Some[+A](get: A) extends Option[A]
case object None extends Option[Nothing] {
def get = throw new Exception("nothing to see here")
def flatMap[B](f: A => Option[B]): Option[B] = this match {
case Some(_) => f(this.get)
case None => None
}
def getOrElse[B >: A](default: => B): B = this match {
case Some(_) => this.get
case None => default
}
def orElse[B >: A](ob: => Option[B]): Option[B] = this match {
case Some(_) => this
case None => ob
}
def filter(f: A => Boolean): Option[A] = this match {
case Some(_) if f(this.get) => this
case _ => None
}
}

val s = Some("B")
s.map(_ => "A")
s.map(_ => "A")
s.filter(_ == "B")

def mean(xs: Seq[Double]): Option[Double] = xs match {
case Nil => None
case _ => 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))))
}

val v = Seq(1.0,2.0,3.0,4.0)
variance(v)

def lift[A,B](f: A => B): Option[A] => Option[B] = _ map f

def map2[A,B,C](optA: Option[A], optB: Option[B])(f: (A,B) => C): Option[C] = {
optA.flatMap(realA => optB.map(realB => f(realA,realB)))
}

def Try[A](a: => A): Option[A] =
try Some(a)
catch { case e: Exception => None }

def sequence[A](a: List[Option[A]]): Option[List[A]] = {
try Some(a.map(x => x.get))
catch { case e: Exception => None }
}

val ss = List(Some(1), Some(2), Some(3), None)
sequence(ss)

def traverse[A,B](a: List[A])(f: A => Option[B]): Option[List[B]] = {
try Some(a.map(x => f(x).get))
catch { case e: Exception => None }
}


49 changes: 25 additions & 24 deletions answers/src/main/scala/fpinscala/errorhandling/Option.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package fpinscala.errorhandling

//hide std library `Option` and `Either`, since we are writing our own in this chapter
import scala.{Option => _, Either => _, _}
//hide std library `Option2` and `Either`, since we are writing our own in this chapter
import scala.annotation.tailrec
import scala.{Either => _, Option => _, _}

sealed trait Option[+A] {
def map[B](f: A => B): Option[B] = this match {
sealed trait Option2[+A] {
def map[B](f: A => B): Option2[B] = this match {
case None => None
case Some(a) => Some(f(a))
}
Expand All @@ -14,42 +15,42 @@ sealed trait Option[+A] {
case Some(a) => a
}

def flatMap[B](f: A => Option[B]): Option[B] =
def flatMap[B](f: A => Option2[B]): Option2[B] =
map(f) getOrElse None

/*
Of course, we can also implement `flatMap` with explicit pattern matching.
*/
def flatMap_1[B](f: A => Option[B]): Option[B] = this match {
def flatMap_1[B](f: A => Option2[B]): Option2[B] = this match {
case None => None
case Some(a) => f(a)
}

def orElse[B>:A](ob: => Option[B]): Option[B] =
def orElse[B>:A](ob: => Option2[B]): Option2[B] =
this map (Some(_)) getOrElse ob

/*
Again, we can implement this with explicit pattern matching.
*/
def orElse_1[B>:A](ob: => Option[B]): Option[B] = this match {
def orElse_1[B>:A](ob: => Option2[B]): Option2[B] = this match {
case None => ob
case _ => this
}

def filter(f: A => Boolean): Option[A] = this match {
def filter(f: A => Boolean): Option2[A] = this match {
case Some(a) if f(a) => this
case _ => None
}
/*
This can also be defined in terms of `flatMap`.
*/
def filter_1(f: A => Boolean): Option[A] =
def filter_1(f: A => Boolean): Option2[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]
case class Some[+A](get: A) extends Option2[A]
case object None extends Option2[Nothing]

object Option {
object Option2 {
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!")
Expand All @@ -71,22 +72,22 @@ object Option {
catch { case e: Exception => 43 }
}

def mean(xs: Seq[Double]): Option[Double] =
def mean(xs: Seq[Double]): Option2[Double] =
if (xs.isEmpty) None
else Some(xs.sum / xs.length)

def variance(xs: Seq[Double]): Option[Double] =
def variance(xs: Seq[Double]): Option2[Double] =
mean(xs) flatMap (m => mean(xs.map(x => math.pow(x - m, 2))))

// a bit later in the chapter we'll learn nicer syntax for
// writing functions like this
def map2[A,B,C](a: Option[A], b: Option[B])(f: (A, B) => C): Option[C] =
a flatMap (aa => b map (bb => f(aa, bb)))
def map2[A,B,C](a: Option2[A], b: Option2[B])(f: (A, B) => C): Option2[C] =
a flatMap (aa => (b map (bb => f(aa, bb))))

/*
Here's an explicit recursive version:
*/
def sequence[A](a: List[Option[A]]): Option[List[A]] =
def sequence[A](a: List[Option2[A]]): Option2[List[A]] =
a match {
case Nil => Some(Nil)
case h :: t => h flatMap (hh => sequence(t) map (hh :: _))
Expand All @@ -96,18 +97,18 @@ object Option {
Scala wrongly infers the result type of the fold as `Some[Nil.type]` and reports a type error (try it!). This is an
unfortunate consequence of Scala using subtyping to encode algebraic data types.
*/
def sequence_1[A](a: List[Option[A]]): Option[List[A]] =
a.foldRight[Option[List[A]]](Some(Nil))((x,y) => map2(x,y)(_ :: _))
def sequence_1[A](a: List[Option2[A]]): Option2[List[A]] =
a.foldRight[Option2[List[A]]](Some(Nil))((x,y) => map2(x,y)(_ :: _))

def traverse[A, B](a: List[A])(f: A => Option[B]): Option[List[B]] =
def traverse[A, B](a: List[A])(f: A => Option2[B]): Option2[List[B]] =
a match {
case Nil => Some(Nil)
case h::t => map2(f(h), traverse(t)(f))(_ :: _)
}

def traverse_1[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)(_ :: _))
def traverse_1[A, B](a: List[A])(f: A => Option2[B]): Option2[List[B]] =
a.foldRight[Option2[List[B]]](Some(Nil))((h,t) => map2(f(h),t)(_ :: _))

def sequenceViaTraverse[A](a: List[Option[A]]): Option[List[A]] =
def sequenceViaTraverse[A](a: List[Option2[A]]): Option2[List[A]] =
traverse(a)(x => x)
}

0 comments on commit b2afb64

Please sign in to comment.