Scala 関数型デザイン&プログラミング 4章 Exercise

Excercise 4.8はあまり自信がない。

// 4.1
def map[B](f: A => B): Option[B] = this match {
  case None => None
  case Some(x) => Some(f(x))
}

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

def getOrElse[B >: A](default: => B): B = this match {
  case None => default
  case Some(x) => x
}

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

def filter(f: A => Boolean): Option[A] = this.flatMap { x => if (f(x)) Some(x) else None }

// 4.2
def variance(xs: Seq[Double]): Option[Double] = {
  mean(xs).map { m => xs.map { x => Math.pow(x - m, 2) } }.flatMap(mean)
}

// 4.3
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) } }

// 4.4
def sequence[A](a: List[Option[A]]): Option[List[A]] = a.foldRight(Some(Nil): Option[List[A]]) { (x, acc) => map2(x, acc)(_ :: _) }

// 4.5
def traverse[A, B](a: List[A])(f: A => Option[B]): Option[List[B]] = a.foldRight(Some(Nil): Option[List[B]]) {
 (x, acc) => map2(f(x), acc)(_ :: _)
}

// 4.6
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(a) => f(a)
}

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 { aa => b.map { bb => f(aa, bb) } }

// 4.7
def sequence[E, A](es: List[Either[E, A]]): Either[E, List[A]] = es.foldRight(Right(Nil): Either[E, List[A]]) { (x, a) => x.map2(a)(_ :: _) }

def traverse[E, A, B](as: List[A])(f: A => Either[E, B]): Either[E, List[B]] = as.foldRight(Right(Nil): Either[E, List[B]]) {
  (x, a) => f(x).map2(a)(_ :: _)
}

// 4.8
// Either[List[E], A]を使用するようにmkPerson、map2を変更する。