Scalaz(19)- Monad: \/ - Monad 版本的 Either
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的更多相关文章
- Ubuntu 系统安装详解 19.04最新版本
Ubuntu 19.04版本系统安装详解 1 .镜像的下载 推荐 阿里云镜像下载 2.安装 1.1.新建虚拟机 注意硬件的兼容性问题 当前只有5.x可以用,其他兼容各位可以尝试下,我也都试过,但只有5 ...
- centos 7.4 安装docker 19.03.6 版本。附带离线安装包
说明: 1.此环境为未安装过docker服务的环境, 如果已经安装,则自行卸载. 2.以下环境中上传的包及离线yum源默认为/home目录下,如无特殊说明,以此目录为准 步骤一:下载docker离线安 ...
- 2015第19周四jquery版本
今天用到一个jquery插件,发现最新版需要jquery2.0以上版本才行,而目前项目在用的版本是1.8.3,自然无法使用,刚看了jquery的主要版本和差异,直接百度搜索无满意结果,最后在百科中给出 ...
- Azkaban3.X的安装(2018年8月19日最新版本)
参考文章: 1.http://azkaban.github.io/azkaban/docs/latest/ 2.http://blog.csdn.net/gaoqida/article/details ...
- Scalaz(41)- Free :IO Monad-Free特定版本的FP语法
我们不断地重申FP强调代码无副作用,这样才能实现编程纯代码.像通过键盘显示器进行交流.读写文件.数据库等这些IO操作都会产生副作用.那么我们是不是为了实现纯代码而放弃IO操作呢?没有IO的程序就是一段 ...
- Scalaz(25)- Monad: Monad Transformer-叠加Monad效果
中间插播了几篇scalaz数据类型,现在又要回到Monad专题.因为FP的特征就是Monad式编程(Monadic programming),所以必须充分理解认识Monad.熟练掌握Monad运用.曾 ...
- Scalaz(17)- Monad:泛函状态类型-State Monad
我们经常提到函数式编程就是F[T].这个F可以被视为一种运算模式.我们是在F运算模式的壳子内对T进行计算.理论上来讲,函数式程序的运行状态也应该是在这个运算模式壳子内的,也是在F[]内更新的.那么我们 ...
- Scalaz(10)- Monad:就是一种函数式编程模式-a design pattern
Monad typeclass不是一种类型,而是一种程序设计模式(design pattern),是泛函编程中最重要的编程概念,因而很多行内人把FP又称为Monadic Programming.这其中 ...
- 泛函编程(23)-泛函数据类型-Monad
简单来说:Monad就是泛函编程中最概括通用的数据模型(高阶数据类型).它不但涵盖了所有基础类型(primitive types)的泛函行为及操作,而且任何高阶类或者自定义类一旦具备Monad特性就可 ...
- Monad 系列
本系列是在学习Monad时在网上找到的一个老外的博客,作者是MikeHadlow,地址是mikehadlow.blogspot.com, 可惜国内访问不了.这个系列对Monad讲解的浅显易懂,而且有 ...
随机推荐
- Java线程:创建与启动
Java线程:创建与启动 一.定义线程 1.扩展java.lang.Thread类. 此类中有个run()方法,应该注意其用法: public void run() 如果该线程是使用独立的 R ...
- Atitit 发帖机系列(6) USRQBN2201 setup spec安装程序的实现规范与标准化解决方案
Atitit 发帖机系列(6) USRQBN2201 setup spec安装程序的实现规范与标准化解决方案 安装主要解决一个问题,就是resin的内容启动路径以及端口..这里是使用的端口8077 主 ...
- fir.im Weekly - iOS9 适配开发教程
期待已久的 iOS 9 发布了,很多人更新完毕得出结论:这是值得升级的版本.随之而来的是适应 iOS9 开发技术.本期 Weekly 收集了一些关于 iOS9 相关的开发资源,希望对你有帮助. iOS ...
- iOS-数据持久化-SQlite3
SQLite3简单介绍 1.ios中数据的存储方式 (1)Plist(NSArray\NSDictionary) (2)Preference(偏好设置\NSUserDefaults) (3)NSCod ...
- SQL SERVER 查询性能优化——分析事务与锁(五)
SQL SERVER 查询性能优化——分析事务与锁(一) SQL SERVER 查询性能优化——分析事务与锁(二) SQL SERVER 查询性能优化——分析事务与锁(三) 上接SQL SERVER ...
- 【QQ技术】群文件报毒怎样下载?~ 变相绕过QQ复杂检验过程
刚才又人问我,要是群文件被鉴定为病毒那怎么下载? 我简单说一下吧: 其实qq客户端过滤比较严的,而web段却还是老一套,很多人说出现这个情况其实是腾讯已经把他库里面的文件删了,其实不然 如果源删了,那 ...
- jxl写入excel实现数据导出功能
@RequestMapping(params = "method=export", method = RequestMethod.GET) public void exportCo ...
- poj2253 Frogger(最短路变型或者最小生成树)
/* 题意:就是源点到终点有多条的路径,每一条路径中都有一段最大的距离! 求这些路径中最大距离的最小值! Dijkstra, Floyd, spfa都是可以的!只不过是将松弛的条件变一下就行了! 想了 ...
- Huge Page 是否是拯救性能的万能良药?
本文将分析是否Huge Page在任何条件下(特别是NUMA架构下)都能带来性能提升. 本博客已经迁移至: http://cenalulu.github.io/ 为了更好的体验,请通过此链接阅读: h ...
- Oracle Dataguard之Real-Time Apply
Oracle Dataguard一共支持三种模式:最大可用模式(Maximum Availability),最大性能模式(Maximum Performance),最大保护模式(Maximum Pro ...