我们在上一篇讨论中介绍了一些基本的由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. Atitti css transition Animation differ区别

    Atitti  css   transition Animation differ区别 1.1. transition的优点在于简单易用,但是它有几个很大的局限.  1 1.2. Transition ...

  2. 一条Select语句丛生到死的处理过程

    以一条普通的“select * from table order by …”语句为例.图2-21中显示为该语句在数据库中各个组件之间的处理过程,各个步骤分别代表: (1)select语句通过网络传送给 ...

  3. 面试小记---外部脚本必须包含 <script> 标签吗?

    外部脚本必须包含 <script> 标签吗? 答案是否定的. 身为小白的我一开始也是以为这句话的对了,因为本来嘛,引用外部脚本不都用的是<script>标签中的src属性吗.所 ...

  4. JavaScript使用正则表达

    正则表达式概述 在前面已经涉及了一些正则表达式的用法,现在将系统地学习正则表达式的语法和用途.正则表达式主要用于进行字符串的模式匹配,例如判断一个字符串是否符合指定格式等.例如在windows下搜索文 ...

  5. .NET面试题解析(01)-值类型与引用类型

      系列文章目录地址: .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引 常见面试题目: 1. 值类型和引用类型的区别? 2. 结构和类的区别? 3. delegate是引用类型还 ...

  6. javase基础复习攻略《三》

    编程语言的发展: 机器语言——直接由计算机的指令组成,指令.地址.数据都是以"0"和"1"的符号串组成,可以被计算机直接执行. 汇编语言——用容易理解和记忆的符 ...

  7. Floyd算法的理解

  8. java中Comparable实现对象的比较

    /* class A implements Comaprable<A>{ } 那么 A x = new A(); 类关系图 Object o = A; Object Comparable ...

  9. Nutch源码阅读进程1---inject

    最近在Ubuntu下配置好了nutch和solr的环境,也用nutch爬取了一些网页,通过solr界面呈现,也过了一把自己建立小搜索引擎的瘾,现在该静下心来好好看看nutch的源码了,先从Inject ...

  10. 50款免费 PSD 名片设计模板源文件下载《下篇》

    名片是陌生人之间建立联系的最便捷.最有效的工具.名片它可能是给你的客户留下正面的印象第一步,另一方面,名片是一个企业最重要和最符合成本效益的营销工具之一,尤其是对于刚刚起步的企业.这里收集了50款免费 ...