scala标准库提供了一个Either类型,它可以说是Option的升级版。与Option相同,Either也有两种状态:Left和Right,分别对应Option的None和Some,不同的是Left可以返回一个值。我们通常用这个值来表述异常信息。scalaz也提供了自己版本的Either,并用\/来分辨表示,以及两种状态-\/和\/-。我想scalaz特别提供\/是有原因的:\/不单是一种类型,它是一种type class。更重要的是\/是一种Monad,具备了函数组合能力(composibility)。如此能够方便把Either功能整合到FP编程中去。我们先看看\/的定义:scalaz/Either.scala

sealed abstract class \/[+A, +B] extends Product with Serializable {
...
def isLeft: Boolean =
this match {
case -\/(_) => true
case \/-(_) => false
} /** Return `true` if this disjunction is right. */
def isRight: Boolean =
this match {
case -\/(_) => false
case \/-(_) => true
}
...
/** Return the right value of this disjunction or the given default if left. Alias for `|` */
def getOrElse[BB >: B](x: => BB): BB =
this match {
case -\/(_) => x
case \/-(b) => b
} /** Return the right value of this disjunction or the given default if left. Alias for `getOrElse` */
def |[BB >: B](x: => BB): BB =
getOrElse(x) /** Return the right value of this disjunction or run the given function on the left. */
def valueOr[BB >: B](x: A => BB): BB =
this match {
case -\/(a) => x(a)
case \/-(b) => b
} /** Return this if it is a right, otherwise, return the given value. Alias for `|||` */
def orElse[AA >: A, BB >: B](x: => AA \/ BB): AA \/ BB =
this match {
case -\/(_) => x
case \/-(_) => this
} /** Return this if it is a right, otherwise, return the given value. Alias for `orElse` */
def |||[AA >: A, BB >: B](x: => AA \/ BB): AA \/ BB =
orElse(x)
...

与Option相同:\/也提供了函数来获取运算值(Right[A]),如getOrElse。那么如何获取异常信息呢?可以用swap后再用getOrElse:

  /** Flip the left/right values in this disjunction. Alias for `unary_~` */
def swap: (B \/ A) =
this match {
case -\/(a) => \/-(a)
case \/-(b) => -\/(b)
} /** Flip the left/right values in this disjunction. Alias for `swap` */
def unary_~ : (B \/ A) =
swap "ah, error!".left[Int].getOrElse("no error") //> res2: Any = no error
"ah, error!".left[Int].swap.getOrElse("no error") //> res3: String = ah, error!
(~"ah, error!".left[Int]).getOrElse("no error") //> res4: String = ah, error!

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

/** A left disjunction
*
* Often used to represent the failure case of a result
*/
final case class -\/[+A](a: A) extends (A \/ Nothing) /** A right disjunction
*
* Often used to represent the success case of a result
*/
final case class \/-[+B](b: B) extends (Nothing \/ B)

\/实现了map和flatMap:

  /** Map on the right of this disjunction. */
def map[D](g: B => D): (A \/ D) =
this match {
case \/-(a) => \/-(g(a))
case b @ -\/(_) => b
}
/** Bind through the right of this disjunction. */
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来证明:

 val epok = for {
a <- \/-()
b <- \/-()
} yield a + b //> epok : scalaz.\/[Nothing,Int] = \/-(5)
val epno = for {
a <- \/-()
c <- -\/("breaking out...")
b <- \/-()
} yield a + b //> epno : scalaz.\/[String,Int] = -\/(breaking out...)
if (epno.isLeft) (~epno).getOrElse("no error") //> res5: Any = breaking out...

\/在for-comprehension里的运算行为与Option一致。不过这个\/写法比较别扭。\/type class为任何类型提供了注入方法left和right: scalaz.syntax/EitherOps.scala

  final def left[B]: (A \/ B) =
-\/(self) final def right[B]: (B \/ A) =
\/-(self)
} trait ToEitherOps { //可以为任何类型A注入方法
implicit def ToEitherOps[A](a: A) = new EitherOps(a)
}

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

 val epok1 = for {
a <- .right
b <- .right
} yield a + b //> epok1 : scalaz.\/[Nothing,Int] = \/-(5)
val epno1 = for {
a <- .right
c <- "breaking out...".left[Int]
b <- .right
} yield a + b //> epno1 : scalaz.\/[String,Int] = -\/(breaking out...)
if (epno1.isLeft) (~epno1).getOrElse("no error") //> res6: Any = breaking out...

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

Scalaz(19)- Monad: \/ - Monad 版本的 Either的更多相关文章

  1. Ubuntu 系统安装详解 19.04最新版本

    Ubuntu 19.04版本系统安装详解 1 .镜像的下载 推荐 阿里云镜像下载 2.安装 1.1.新建虚拟机 注意硬件的兼容性问题 当前只有5.x可以用,其他兼容各位可以尝试下,我也都试过,但只有5 ...

  2. centos 7.4 安装docker 19.03.6 版本。附带离线安装包

    说明: 1.此环境为未安装过docker服务的环境, 如果已经安装,则自行卸载. 2.以下环境中上传的包及离线yum源默认为/home目录下,如无特殊说明,以此目录为准 步骤一:下载docker离线安 ...

  3. 2015第19周四jquery版本

    今天用到一个jquery插件,发现最新版需要jquery2.0以上版本才行,而目前项目在用的版本是1.8.3,自然无法使用,刚看了jquery的主要版本和差异,直接百度搜索无满意结果,最后在百科中给出 ...

  4. Azkaban3.X的安装(2018年8月19日最新版本)

    参考文章: 1.http://azkaban.github.io/azkaban/docs/latest/ 2.http://blog.csdn.net/gaoqida/article/details ...

  5. Scalaz(41)- Free :IO Monad-Free特定版本的FP语法

    我们不断地重申FP强调代码无副作用,这样才能实现编程纯代码.像通过键盘显示器进行交流.读写文件.数据库等这些IO操作都会产生副作用.那么我们是不是为了实现纯代码而放弃IO操作呢?没有IO的程序就是一段 ...

  6. Scalaz(25)- Monad: Monad Transformer-叠加Monad效果

    中间插播了几篇scalaz数据类型,现在又要回到Monad专题.因为FP的特征就是Monad式编程(Monadic programming),所以必须充分理解认识Monad.熟练掌握Monad运用.曾 ...

  7. Scalaz(17)- Monad:泛函状态类型-State Monad

    我们经常提到函数式编程就是F[T].这个F可以被视为一种运算模式.我们是在F运算模式的壳子内对T进行计算.理论上来讲,函数式程序的运行状态也应该是在这个运算模式壳子内的,也是在F[]内更新的.那么我们 ...

  8. Scalaz(10)- Monad:就是一种函数式编程模式-a design pattern

    Monad typeclass不是一种类型,而是一种程序设计模式(design pattern),是泛函编程中最重要的编程概念,因而很多行内人把FP又称为Monadic Programming.这其中 ...

  9. 泛函编程(23)-泛函数据类型-Monad

    简单来说:Monad就是泛函编程中最概括通用的数据模型(高阶数据类型).它不但涵盖了所有基础类型(primitive types)的泛函行为及操作,而且任何高阶类或者自定义类一旦具备Monad特性就可 ...

  10. Monad 系列

    本系列是在学习Monad时在网上找到的一个老外的博客,作者是MikeHadlow,地址是mikehadlow.blogspot.com,  可惜国内访问不了.这个系列对Monad讲解的浅显易懂,而且有 ...

随机推荐

  1. iOS-------应用性能调优的25个建议和技巧

    性能对 iOS 应用的开发尤其重要,如果你的应用失去反应或者很慢,失望的用户会把他们的失望写满App Store的评论.然而由于iOS设备的限制,有时搞好性能是一件难事.开发过程中你会有很多需要注意的 ...

  2. Android WebView 总结 —— Java和JavaScript交互

    交互如何实现 实现Java和js交互十分便捷.通常只需要以下几步. WebView开启JavaScript脚本执行 WebView设置供JavaScript调用的交互接口. 客户端和网页端编写调用对方 ...

  3. 学习ASP.NET MVC(四)——我的第一个ASP.NET MVC 实体对象

    今天我将根据数据库中的表结构添加一些类.这些类将成为这个ASP.NET MVC应用程序中“模型”的一部分.       我们使用Entity Framework(实体框架)来定义和使用这些模型类,并且 ...

  4. SQL SERVER 2005/2008 中关于架构的理解(二)

    本文上接SQL SERVER 2005/2008 中关于架构的理解(一)      架构的作用与示例 用户与架构(schema)分开,让数据库内各对象不再绑在某个用户账号上,可以解决SQL SERVE ...

  5. How Google TestsSoftware - Part Five

    Instead of distinguishingbetween code, integration and system testing, Google uses the language ofsm ...

  6. 使用swoole和websocket结合来制造弹幕

    在知乎上无意中看到了一篇有关这个的话题https://zhuanlan.zhihu.com/p/23992890,刚好没事也好久没弄swoole了就自己按照知乎上的那篇文站实操了一下 那个试验中有几个 ...

  7. 快速入门系列--WCF--07传输安全、授权与审核

    这部分主要涉及企业级应用的安全问题,一般来说安全框架主要提供3个典型的安全行为:认证.授权和审核.除了典型的安全问题,对于一个以消息作为通信手段的分布式应用,还需要考虑消息保护(Message Pro ...

  8. OpenCascade BRep Format Description

    OpenCascade BRep Format Description eryar@163.com 摘要Abstract:本文结合OpenCascade的BRep格式描述文档和源程序,对BRep格式进 ...

  9. JSP网站开发基础总结《十四》

    对于JSP的知识总结,已经为大家分享的差不多了,本篇就为大家做一下最后总结,本篇总结的主题是文件上传和下载,在之前的随笔中也有为大家分享过文件上传和下载的知识,不过都是通过JAVA提供的上传下载类实现 ...

  10. JSP网站开发基础总结《二》

    有了上一篇的学习,我相信大家对于JSP一定有了一定的认识,从今天开始我们真正开启JSP模式,如果你有HTML的基础,那学起JSP来也就方便了很多了,首先JSP做为网站开发语言,它与HTML有很多相似的 ...