我们在上一篇讨论中介绍了一些基本的由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. Atitit. Atiposter 发帖机 新特性 poster new feature v11  .docx

    Atitit. Atiposter 发帖机 新特性 poster new feature v11  .docx 1.1.  版本历史1 2. 1. 未来版本规划2 2.1. V12版本规划2 2.2. ...

  2. 为什么获取的System.Web.HttpContext.Current值为null,HttpContext对象为null时如何获取程序(站点)的根目录

    ASP.NET提供了静态属性System.Web.HttpContext.Current,因此获取HttpContext对象就非常方便了.也正是因为这个原因,所以我们经常能见到直接访问System.W ...

  3. 学习ASP.NET MVC(八)——“Code First Migrations ”工具

    在本篇文章中,我们学习如何使用实体框架的“Code First Migrations ”(也称为代码先行功能)工具,使用其中的“迁移”功能对模型类进行一些修改,同时同步更新对应数据库的表结构. 默认情 ...

  4. HTML中的title换行问题

    有时我们需要在html元素的title中换行显示信息.以下几种方法均可以实现: 直接在titile属性中使用换行,如下所示: asd">asdsadsad</a> 在tit ...

  5. Android入门(十七)Android多线程

    原文链接:http://www.orlion.ga/670/ 一.在子线程中更新UI Android中不允许在子线程中更新UI,只能在主线程中更新,但是我们有时候必须在子线程中执行一些耗时的任务,然后 ...

  6. tomcat触发ServletContext初始化监听事件的源码(原创)

    tomcat 8.0.36 知识点: 动态监听器的好处可以根据环境条件进行选择性添加. 静态监听器有七类. ServletContextAttributeListener ServletRequest ...

  7. Spark入门实战系列--6.SparkSQL(中)--深入了解SparkSQL运行计划及调优

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 1.1  运行环境说明 1.1.1 硬软件环境 线程,主频2.2G,10G内存 l  虚拟软 ...

  8. 怎么让composer加速

    composer install 为什么这么慢? 下面是一个composer install(在没有composer cache的情况下)做的所有事情: [vagrant@localhost comp ...

  9. Shiro —— Spring 环境下的使用

    一.使用 1.搭建基础环境 (1)导入 Spring 和 Shiro 的 Jar 包 正常导入 spring jar包 导入日志包 log4j-1.2.15.jar slf4j-api-1.6.1.j ...

  10. 30天C#基础巩固------this,base,string中的方法,StringBuilder性能

    这里主要是记录下自己学习笔记,希望有个地方在以后可以看到自己走过的路. 关于之前多态的知识有一个口诀,很好理解里面的override和new,virtual关键字. "new则隐藏,over ...