我们在上一篇讨论中介绍了一些基本的由scalaz提供的typeclass。这些基本typeclass主要的作用是通过操作符来保证类型安全,也就是在前期编译时就由compiler来发现错误。在这篇讨论中我希望能按照scalaz的格式设计自己的typeclass并能使之融入scalaz库结构里去。

我们来设计一个NoneZero typeclass。这个NoneZero typeclass能确定目标类型值是否为空,如:

0.nonZero = false

3.nonZero = true

"".nonZero = false

"value".nonZero = true

List().nonZero = false

List(1,2,3).nonZero = true

首先是trait: (定义typeclass行为)

 trait NonZero[A] {
def nonZero(a: A): Boolean
}

现在NonZero typeclass只有一项功能或行为,就是这个抽象函数NonZero:对任何类型A值a,返回Boolean结果。

为了方便使用NoneZero typeclass,我们在伴生对象里定义NonZero[A]的构建函数,这样我们就不需要每次都重新实现抽象行为函数nonZero了:

 object NonZero {
def create[A](f: A => Boolean): NonZero[A] = new NonZero[A] {
def nonZero(a: A): Boolean = f(a)
}
}

只要我们提供一个f: A => Boolean函数就能用create来构建一个NonZero[A]实例。实际上这个f函数定义了类型A在NonZero tyoeclass中的具体行为。

下一步是注入操作方法:

 class NonZeroOps[A](a: A)(implicit ev: NonZero[A]) {
def isNonZero: Boolean = ev.nonZero(a)
}

我们注入了一个操作方法isNonZero。注意:注入方法是针对所有类型A的,所以需要NonZero[A]作为参数。

跟着就是隐式作用域解析了(implicit resolution):

 object ToNonZeroOps {
implicit def toNonZeroOps[A](a: A)(implicit ev: NonZero[A]) = new NonZeroOps[A](a)
}

这是一个隐式视域(implicit view):从类型A转换到NonZeroOps[A]。这样类型A就具备isNonZero这个操作方法了。

我们按scalaz惯例在object NonZero放一个默认隐式转换:

 object NonZero {
def create[A](f: A => Boolean): NonZero[A] = new NonZero[A] {
def nonZero(a: A): Boolean = f(a)
}
implicit val intNZInstance: NonZero[Int] = create {
case => false
case _ => true
}
}

注意我们在create参数里使用了partial function。

然后试试在Int类型上使用:

 import ToNonZeroOps._

 .isNonZero                                      //> res0: Boolean = true
.isNonZero //> res1: Boolean = false
.isNonZero //> res2: Boolean = true

不错,已经可以用了。再试试其它即兴类型:

 import ToNonZeroOps._
implicit val stringNZInstance: NonZero[String] = NonZero.create {
case "" => false
case _ => true
} //> stringNZInstance : scalaz.ex5.NonZero[String] = scalaz.ex5$NonZero$$anon$1@
//| 1c655221
implicit val booleanNZInstance: NonZero[Boolean] = NonZero.create { b => b }
//> booleanNZInstance : scalaz.ex5.NonZero[Boolean] = scalaz.ex5$NonZero$$anon$
//| 1@6aaa5eb0 implicit def listNZInstance[A]: NonZero[List[A]] = NonZero.create {
case Nil => false
case _ => true
} //> listNZInstance: [A]=> scalaz.ex5.NonZero[List[A]] "".isNonZero //> res0: Boolean = false
"not empty".isNonZero //> res1: Boolean = true
true.isNonZero //> res2: Boolean = true
false.isNonZero //> res3: Boolean = false
List(,,).isNonZero //> res4: Boolean = true
List("a","b").isNonZero //> res5: Boolean = true
List().isNonZero //> res6: Boolean = false .isNonZero //> res7: Boolean = true
.isNonZero //> res8: Boolean = false
.isNonZero //> res9: Boolean = true

我把完整的代码贴在下面吧,供大家练习参考:

 trait NonZero[A] {
def nonZero(a: A): Boolean
}
object NonZero {
def create[A](f: A => Boolean): NonZero[A] = new NonZero[A] {
def nonZero(a: A): Boolean = f(a)
}
implicit val intNZInstance: NonZero[Int] = create {
case => false
case _ => true
}
}
class NonZeroOps[A](a: A)(implicit ev: NonZero[A]) {
def isNonZero: Boolean = ev.nonZero(a)
}
object ToNonZeroOps {
implicit def toNonZeroOps[A](a: A)(implicit ev: NonZero[A]) = new NonZeroOps[A](a)
} import ToNonZeroOps._
implicit val stringNZInstance: NonZero[String] = NonZero.create {
case "" => false
case _ => true
} //> stringNZInstance : scalaz.ex5.NonZero[String] = scalaz.ex5$NonZero$$anon$1@
//| 1c655221
implicit val booleanNZInstance: NonZero[Boolean] = NonZero.create { b => b }
//> booleanNZInstance : scalaz.ex5.NonZero[Boolean] = scalaz.ex5$NonZero$$anon$
//| 1@6aaa5eb0 implicit def listNZInstance[A]: NonZero[List[A]] = NonZero.create {
case Nil => false
case _ => true
} //> listNZInstance: [A]=> scalaz.ex5.NonZero[List[A]] "".isNonZero //> res0: Boolean = false
"not empty".isNonZero //> res1: Boolean = true
true.isNonZero //> res2: Boolean = true
false.isNonZero //> res3: Boolean = false
List(,,).isNonZero //> res4: Boolean = true
List("a","b").isNonZero //> res5: Boolean = true
List().isNonZero //> res6: Boolean = false .isNonZero //> res7: Boolean = true
.isNonZero //> res8: Boolean = false
.isNonZero //> res9: Boolean = true

Scalaz(5)- typeclass:my typeclass scalaz style-demo的更多相关文章

  1. Scalaz(43)- 总结 :FP就是实用的编程模式

    完成了对Free Monad这部分内容的学习了解后,心头豁然开朗,存在心里对FP的疑虑也一扫而光.之前也抱着跟大多数人一样的主观概念,认为FP只适合学术性探讨.缺乏实际应用.运行效率低,很难发展成现实 ...

  2. Scalaz(22)- 泛函编程思维: Coerce Monadic Thinking

    马上进入新的一年2016了,来点轻松点的内容吧.前面写过一篇关于用Reader实现依赖注入管理的博文(Scalaz(16)- Monad:依赖注入-Dependency Injection By Re ...

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

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

  4. Scalaz(53)- scalaz-stream: 程序运算器-application scenario

    从上面多篇的讨论中我们了解到scalaz-stream代表一串连续无穷的数据或者程序.对这个数据流的处理过程就是一个状态机器(state machine)的状态转变过程.这种模式与我们通常遇到的程序流 ...

  5. MySQL数据分析-(15)表补充:存储引擎

    大家好,我是jacky,很高兴继续跟大家分享<MySQL数据分析实战>,今天跟大家分享的主题是表补充之存储引擎: 我们之前学了跟表结构相关的一些操作,那我们看一下创建表的SQL模型: 在我 ...

  6. STL笔记(6)标准库:标准库中的排序算法

    STL笔记(6)标准库:标准库中的排序算法 标准库:标准库中的排序算法The Standard Librarian: Sorting in the Standard Library Matthew A ...

  7. java中文乱码解决之道(三)-----编码详情:伟大的创想---Unicode编码

    随着计算机的发展.普及,世界各国为了适应本国的语言和字符都会自己设计一套自己的编码风格,正是由于这种乱,导致存在很多种编码方式,以至于同一个二进制数字可能会被解释成不同的符号.为了解决这种不兼容的问题 ...

  8. Android Animation学习(五) ApiDemos解析:容器布局动画 LayoutTransition

    Android Animation学习(五) ApiDemos解析:容器布局动画 LayoutTransition Property animation系统还提供了对ViewGroup中的View改变 ...

  9. Android Animation学习(四) ApiDemos解析:多属性动画

    Android Animation学习(四) ApiDemos解析:多属性动画 如果想同时改变多个属性,根据前面所学的,比较显而易见的一种思路是构造多个对象Animator , ( Animator可 ...

  10. Android Animation学习(三) ApiDemos解析:XML动画文件的使用

    Android Animation学习(三) ApiDemos解析:XML动画文件的使用 可以用XML文件来定义Animation. 文件必须有一个唯一的根节点: <set>, <o ...

随机推荐

  1. php-fpm进程数优化

    php-fpm未优化网友反映的问题 1.最近将Wordpress迁移至阿里云.由于自己的服务器是云服务器,硬盘和内存都比较小,所以内存经常不够使,通过ps ax命令查看后,发现启动php-fpm进程数 ...

  2. [CSS]复选框单选框与文字对齐问题的研究与解决.

    前言:今天碰到的这个问题, 恰好找到一个很好的博文, 在这里转载过来 学习下. 原文地址:复选框单选框与文字对齐问题的研究与解决. 目前中文网站上面的文字,就我的个人感觉而言,绝大多数网站的主流文字大 ...

  3. android上引入七牛 上传图片或者文件 最终整理版本(可用)

    前言: 以下是引入七牛的步骤,以及在七牛中上传文件和获取文件private 私密地址. 生成上传凭证和获取下载凭证 具体如果使用过程有什么疑问可以加QQ(备注:七牛问题). 1:导入相关的包(注意是4 ...

  4. leancloud 用户登录(调用API) 教程

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; ...

  5. 谈谈java的运行机制

    1.高级语言的运行机制 我们编程都是用的高级语言(写汇编和机器语言的大牛们除外),计算机不能直接理解高级语言,只能理解和运行机器语言,所以必须要把高级语言翻译成机器语言,计算机才能运行高级语言所编写的 ...

  6. Session监听器

    Session监听器,是用来监听session对象创建和关闭的.有时我们需要在session创建或关闭时执行一些操作.这是就可以使用Session Listenner. .在项目的web.xml文件中 ...

  7. 后端码农谈前端(CSS篇)第七课:定位与浮动

    一.定位: 1.定位的理解 (1)相对定位 相对定位是一个非常容易掌握的概念.如果对一个元素进行相对定位,它将出现在它所在的位置上.然后,可以通过设置垂直或水平位置,让这个元素"相对于&qu ...

  8. Twitter Storm安装配置(Ubuntu系统)单机版

    要使用storm首先要安装以下工具:JDK.Python.zookeeper.zeromq.jzmq.storm (注:各个模块都是独立的,如果安装失败或者卡顿可以单独百度某个模块的安装,都是可以的. ...

  9. (转)sql的join图解

    假设我们有两张表,Table A是左边的表,Table B是右边的表. 其各有四条记录,其中有两条记录是相同的,如下所示: 1 id name       id  name 2 -- ----     ...

  10. android布局文件中android:icon="?attr/menuIconCamera"找不到对应图标路径

    如 <item android:id="@+id/camera" android:title="Camera" android:icon="?a ...