Saturday, October 24, 2015

Functional programming in Scala, Chapter 4, Either type

object Example {

//  sealed trait Option[+A] {
//    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 match {
//      case None => None
//      case Some(x) => f(x) match {
//        case None => None
//        case y => y
//      }
//    }
//
//    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] = {
//      if (this == None) ob
//      else this
//    }
//
//    def filter(f: A => Boolean): Option[A] = this match {
//      case None => None
//      case y@Some(x) => if (f(x)) y else None
//    }
//  }
//
//  case class Some[+A](val get: A) extends Option[A]
//
//  case object None extends Option[Nothing]
//
//  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 lift[A, B](f: A => B): Option[A] => Option[B] = {
//    _ map f
//  }
//
//  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))
//    }
//  }
//  def map2a[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 map2b[A, B, C](a: Option[A], b: Option[B])(f: (A, B) => C): Option[C] = {
//    for {
//      aa <- a
//      bb <- b
//    } yield f(aa, bb)
//  }
//
//
//
//  def sequence[A](a: List[Option[A]]): Option[List[A]] =
//    a.foldRight[Option[List[A]]](Some(Nil))((x,y) => map2(x,y)(_ :: _))
//
//
//  def parseInts(as: List[String]): Option[List[Int]] = {
//    traverse(as)(a => Try(a.toInt))
//  }
//
//  def traverse1[A, B](as: List[A])(f: A => Option[B]): Option[List[B]] = {
//    as match {
//      case Nil => Some(Nil)
//      case x :: xs => map2(f(x), traverse(as)(f))(_ :: _)
//    }
//  }
//  def traverse[A, B](as: List[A])(f: A => Option[B]): Option[List[B]] = {
//    as.foldRight[Option[List[B]]](Some(Nil))((h, t) => map2(f(h), t)(_ :: _))
//  }
//
//
//
//  def sequence2[A](a: List[Option[A]]): Option[List[A]] =
//    traverse(a)(x => x)
//
//  def positiveOption(x: Int): Option[Int] = {
//    if(x > 0) Some(x) else None
//  }
//
//  def Try[A](a: => A): Option[A] =
//    try Some(a)
//    catch {
//      case e: Exception => {
//        println(e)
//        None
//      }
//    }
//
//  def parseInsuranceRateQuote(age: String, numberOfSpeedingTickets: String): Option[Double] = {
//    val optAge: Option[Int] = Try(age.toInt)
//    val optTickets: Option[Int] = Try(numberOfSpeedingTickets.toInt)
//    map2(optAge, optTickets)(insuranceRateQuote)
//  }
//
//  def insuranceRateQuote(age: Int, numberOfSpeedingTickets: Int): Double = {
//    age + (numberOfSpeedingTickets * 2)
//  }

  sealed trait Either[+E, +A] {
    def map[B](f: A => B): Either[E, B] = {
      this match {
        case left @ Left(e) => left
        case Right(res) => Right(f(res))
      }
    }
    def flatMap[EE >: E, B](f: A => Either[EE, B]): Either[EE, B] = {
      this match {
        case left @ Left(_) => left
        case Right(res) => f(res)
      }
    }
    def orElse[EE >: E, B >: A](b: => Either[EE, B]): Either[EE, B] = {
      this match {
        case right @ Right(_) => right
        case Left(_) => b
      }
    }
    def map2[EE >: E, B, C](b: Either[EE, B])(f: (A, B) => C): Either[EE, C] = {
      (this, b) match {
        case (e@Left(_), _) => e
        case (_, e@Left(_)) => e
        case (Right(x), Right(y)) => Right(f(x, y))
      }
    }
  }
  case class Left[+E](value: E) extends Either[E, Nothing]
  case class Right[+A](value: A) extends Either[Nothing, A]

  def mean(xs: IndexedSeq[Double]): Either[String, Double] = {
    if(xs.isEmpty) Left("Mean of empty list.")
    else Right(xs.sum / xs.length)
  }

  def safeDiv(x: Int, y: Int): Either[Exception, Int] = {
    try Right(x / y)
    catch {
      case e: Exception => Left(e)
    }
  }

  def Try[A](a: => A): Either[Exception, A] = {
    try Right(a)
    catch {
      case e: Exception => Left(e)
    }
  }

  def insuranceRateQuote(a: Double, b: Double) = {
    a + b * 2
  }

  def parseInsuranceRateQuote(
                             age: String,
                             numberOfSpeedingTickets: String
                               ): Either[Exception, Double] = {
    for{
      a <- Try {age.toDouble}
      b <- Try {numberOfSpeedingTickets.toDouble}
    } yield insuranceRateQuote(a, b)
  }

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

  def sequence[E, A](es: List[Either[E, A]]): Either[E, List[A]] = traverse(es)(x => x)

  case class Person(name: Name, age: Age)
  sealed class Name(val value: String)
  sealed class Age(val value: Int)
  def mkName(name: String): Either[String, Name] = {
    if(name.isEmpty) Left("Name is empty")
    else Right(new Name(name))
  }
  def mkAge(age: Int): Either[String, Age] = {
    if(age < 0) Left("Age is out of range")
    else Right(new Age(age))
  }
  def mkPerson(name: String, age: Int): Either[String, Person] = {
    mkName(name).map2(mkAge(age))(Person(_, _))
  }

}


object Test {
  import Example._

  parseInsuranceRateQuote("11.2", "3.2")
  parseInsuranceRateQuote("fdas", "2.3")
  parseInsuranceRateQuote("2.3", "world")

}

0 comments: