博客
关于我
Scalaz(19)- Monad: \/ - Monad 版本的 Either
阅读量:459 次
发布时间:2019-03-06

本文共 2537 字,大约阅读时间需要 8 分钟。

Scala标准库提供了一个Either类型,它是一个对Option的升级版。与Option类似,Either也有两种状态:Left和Right,分别对应Option的None和Some。但是Left可以返回一个值,这通常用于表示异常信息。

scalaz提供了自己的Either实现,并使用/来区分Left和Right。/不仅仅是一个类型,它还是一个Monad,具备了函数组合的能力。这使得它能够方便地整合到函数式编程中。

我们先来看/的定义:

sealed abstract class \/[+A, +B] extends Product with Serializable {  def isLeft: Boolean = this match {    case -\/(_) => true    case \/-(_) => false  }  def isRight: Boolean = this match {    case -\/(_) => false    case \/-(_) => true  }  def getOrElse[BB >: B](x: => BB): BB = this match {    case -\/(_) => x    case \/-(b) => b  }  def |[BB >: B](x: => BB): BB = getOrElse(x)  def valueOr[BB >: B](x: A => BB): BB = this match {    case -\/(a) => x(a)    case \/--(b) => b  }  def orElse[AA >: A, BB >: B](x: => AA \/ BB): AA \/ BB = this match {    case -\/(_) => x    case \/--(b) => this  }  def |||[AA >: A, BB >: B](x: => AA \/ BB): AA \/ BB = orElse(x)}

与Option相同,/也提供了获取运算值的方法,如getOrElse。要获取异常信息,可以使用swap后再用getOrElse:

def swap: (B \/ A) = this match {  case -\/(a) => \/-(a)  case \/--(b) => -\/(b)}

与Option一样,/也有两种状态:

final case class -\/[+A](a: A) extends (A \/ Nothing)final case class \/-[+B](b: B) extends (Nothing \/ B)

/实现了map和flatMap:

def map[D](g: B => D): (A \/ D) = this match {  case \/-(a) => \/-(g(a))  case b @ -\/(_) => b}def flatMap[AA >: A, D](g: B => (AA \/ D)): (AA \/ D) = this match {  case a @ -\/(_) => a  case \/-(b) => g(b)}

注意到flatMap:如果状态为/- 则执行g(b),如果状态为-/ 则立即停止运算返回-/状态。这与Option的功能相当。

我们可以用for-comprehension来证明:

1 val epok = for {  2     a <- \/-(3)  3     b <- \/-(2)  4 } yield a + b// 结果:epok : scalaz.\/[Nothing,Int] = \/-(5)5 val epno = for {  6     a <- \/-(3)  7     c <- "breaking out...".left[Int]  8     b <- \/-(2)  9 } yield a + b// 结果:epno : scalaz.\/[String,Int] = -\/(breaking out...)10 if (epno.isLeft) (~epno).getOrElse("no error")// 结果:res5: Any = breaking out...

这样表述是不是清晰直白多了。

与Option一样,/也有两种状态。/type class为任何类型提供了注入方法left和right:

final def left[B]: (A \/ B) = -\/(self)final def right[B]: (B \/ A) = \/-(self)trait ToEitherOps {  implicit def ToEitherOps[A](a: A) = new EitherOps(a)}

现在这个for-comprehension可以这样写:

1 val epok1 = for {  2     a <- 3.right  3     b <- 2.right  4 } yield a + b// 结果:epok1 : scalaz.\/[Nothing,Int] = \/-(5)5 val epno1 = for {  6     a <- 3.right  7     c <- "breaking out...".left[Int]  8     b <- 2.right  9 } yield a + b// 结果:epno1 : scalaz.\/[String,Int] = -\/(breaking out...)10 if (epno1.isLeft) (~epno1).getOrElse("no error")// 结果:res6: Any = breaking out!

这样表述是不是清晰直白多了。

是不是觉得这样写起来更直观呢?通过这些例子可以看出,Either在处理错误信息时非常有优势。

转载地址:http://gyefz.baihongyu.com/

你可能感兴趣的文章
NO 157 去掉禅道访问地址中的zentao
查看>>
no available service ‘default‘ found, please make sure registry config corre seata
查看>>
no connection could be made because the target machine actively refused it.问题解决
查看>>
No Datastore Session bound to thread, and configuration does not allow creation of non-transactional
查看>>
No fallbackFactory instance of type class com.ruoyi---SpringCloud Alibaba_若依微服务框架改造---工作笔记005
查看>>
No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalanc
查看>>
No mapping found for HTTP request with URI [/...] in DispatcherServlet with name ...的解决方法
查看>>
No mapping found for HTTP request with URI [/logout.do] in DispatcherServlet with name 'springmvc'
查看>>
No module named 'crispy_forms'等使用pycharm开发
查看>>
No module named cv2
查看>>
No module named tensorboard.main在安装tensorboardX的时候遇到的问题
查看>>
No module named ‘MySQLdb‘错误解决No module named ‘MySQLdb‘错误解决
查看>>
No new migrations found. Your system is up-to-date.
查看>>
No qualifying bean of type XXX found for dependency XXX.
查看>>
No resource identifier found for attribute 'srcCompat' in package的解决办法
查看>>
no session found for current thread
查看>>
No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android
查看>>
NO.23 ZenTaoPHP目录结构
查看>>
no1
查看>>
NO32 网络层次及OSI7层模型--TCP三次握手四次断开--子网划分
查看>>