Skip to content

Instantly share code, notes, and snippets.

@heliocentrist
Created February 20, 2017 15:27
Show Gist options
  • Save heliocentrist/91f7efc4ffb58b66a0e46223952bac51 to your computer and use it in GitHub Desktop.
Save heliocentrist/91f7efc4ffb58b66a0e46223952bac51 to your computer and use it in GitHub Desktop.
//package ch4
// 4.1
import scala.util.Left
import scala.{Either => _, Left => _, Right => _, None => _, Option => _, Some => _, _}
case class Some[+A](get: A) extends Option[A]
case object None extends Option[Nothing]
sealed trait Option[+A] {
def map[B](f: A => B): Option[B] = {
this match {
case None => None
case Some(a) => Some(f(a))
}
}
def getOrElse[B >: A](default: => B): B =
this match {
case None => default
case Some(b) => b
}
def flatMap[B](f: A => Option[B]): Option[B] =
this.map(f).getOrElse(None)
def orElse[B >: A](ob: => Option[B]): Option[B] =
this.map(a => Some(a)).getOrElse(ob)
def filter(f: A => Boolean): Option[A] =
this.flatMap(a => if (f(a)) Some(a) else None)
}
object Option {
def mean(xs: Seq[Double]): Option[Double] =
if (xs.isEmpty) None
else Some(xs.sum/xs.length)
// 4.2
def variance(xs: Seq[Double]): Option[Double] = {
mean(xs).flatMap(m => mean(xs.map(x => math.pow(x - m, 2))))
}
// 4.3
def map2[A,B,C](a: Option[A], b: Option[B])(f: (A, B) => C): Option[C] =
a.flatMap(x => b.map(y => f(x,y)))
// 4.4
def sequence[A](a: List[Option[A]]): Option[List[A]] =
a.foldRight[Option[List[A]]](Some(Nil))((x, y) => map2(x,y)(_ :: _))
// 4.5
def traverse[A, B](a: List[A])(f: A => Option[B]): Option[List[B]] =
a.foldRight[Option[List[B]]](Some(Nil))((a, b) => map2(f(a), b)(_ :: _))
}
case class Left[+E](value: E) extends Either[E, Nothing]
case class Right[+A](value: A) extends Either[Nothing, A]
// 4.6
sealed trait Either[+E, +A] {
def map[B](f: A => B): Either[E, B] =
this match {
case Left(e) => Left(e)
case Right(a) => Right(f(a))
}
def flatMap[EE >: E, B](f: A => Either[EE, B]): Either[EE, B] =
this match {
case Left(e) => Left(e)
case Right(bb) => f(bb)
}
def orElse[EE >: E,B >: A](b: => Either[EE, B]): Either[EE, B] =
this match {
case Left(_) => b
case Right(a) => Right(a)
}
def map2[EE >: E, B, C](b: Either[EE, B])(f: (A, B) => C): Either[EE, C] =
this.flatMap(a => b.map(bb => f(a,bb)))
}
// 4.7
object Either {
def sequence[E, A](es: List[Either[E, A]]): Either[E, List[A]] =
es.foldRight[Either[E, List[A]]](Right(Nil))((h, acc) => h.map2(acc)(_ :: _))
def sequence1[E, A](es: List[Either[E, A]]): Either[E, List[A]] =
es match {
case Nil => Right(Nil)
case h :: t => h.flatMap(hh => sequence1(t).map(tt => hh :: tt))
}
def traverse[E, A, B](as: List[A])(f: A => Either[E, B]): Either[E, List[B]] =
as match {
case Nil => Right(Nil)
case h :: t => f(h).flatMap(hh => traverse(t)(f).map(tt => hh :: tt))
}
def sequence2[E, A](es: List[Either[E, A]]): Either[E, List[A]] =
traverse(es)(x => x)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment