Option不会告诉我们在异常条件下发生了什么错误,它只是给我们一个None,表示没有可用的值。但是有时候我们想知道更多,比如想要一个字符串给出更多的信息或者异常发生时想知道实际错误是什么。这时候我们需要Either数据类型。
Either数据类型
sealed trait Either[+E, +A] {
}
case class Left[+E](e: E) extends Either[E, Nothing]
case class Right[+A](a: A) extends Either[Nothing, A]
练习 4.6
实现Either版的map、flatMap、orElse和map2函数
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(e) => b
case _ => this
}
def map2[EE >: E, B, C](eb: Either[EE, B])(f: (A, B) => C): Either[EE, C] =
for {
a <- this
b <- eb
} yield f(a, b)
练习 4.7
对Either实现sequence和traverse,遇到错误返回第一个错误。
def sequence[E, A](li: List[Either[E, A]]): Either[E, List[A]] = {
def loop(n: Int, res: Either[E, List[A]]): Either[E, List[A]] = n match {
case -1 => res
case _ => li(n) match {
case Left(e) => Left(e)
case Right(a) => loop(n - 1, res.map(a :: _))
}
}
loop(li.length - 1, Right(Nil))
}
def traverse[E, A, B](li: List[A])(f: A => Either[E, B]): Either[E, List[B]] =
sequence(li.map(f))
网友评论