我们在上一篇讨论中介绍了一些基本的由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. python学习 数据类型之序列

    一.序列(本文使用python3.5)############################################################# 列表.元组 字符窜都是序列#特点:#1 ...

  2. node.js 简介

    简介:     Node,是一个可以让 JavaScript 运行在服务器端的平台.它可以让 JavaScript 脱离浏览器的束缚运行在一般的服务器环境下     Node.js 是一个为实时Web ...

  3. vuejs件同一个挂载点上切换组

    vuejs件同一个挂载点上切换组 动态组件 http://cn.vuejs.org/guide/components.html#动态组件 多个组件可以使用同一个挂载点,然后动态地在它们之间切换.使用保 ...

  4. 12.创建一个Point类,有成员变量x,y,方法getX(),setX(),还有一个构造方 法初始化x和y。创建类主类A来测试它。

    package java1; public class Point { int x; int y; Point(int x,int y) { this.x = x; this.y = y; } pub ...

  5. 手把手教你实现一个完整的 Promise

    用过 Promise,但是总是有点似懂非懂的感觉,也看过很多文章,还是搞不懂 Promise的 实现原理,后面自己边看文章,边调试代码,终于慢慢的有感觉了,下面就按自己的理解来实现一个 Promise ...

  6. python的继承

    继承是面向对象的重要特征之一,继承是两个类或者多个类之间的父子关系,子进程继承了父进程的所有公有实例变量和方法.继承实现了代码的重用.重用已经存在的数据和行为,减少代码的重新编写,python在类名后 ...

  7. JSON学习之二

    1.JSON语法是JavaScript对象表示法的子集,语法规则: **数据在名称/值对中 **数据由逗号分隔 **花括号保存对象 **方括号保存数组 2.JSON名称/值对:JSON数据的书写格式是 ...

  8. 文本溢出text-overflow和文本阴影text-shadow

    前面的话 CSS3新增了一些关于文本的样式,其中text-overflow文本溢出和text-shadow文本阴影有些特别.因为它们有对应的overflow溢出属性和box-shadow盒子阴影属性. ...

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

    经过前几篇的摸爬滚打,下面我们就开始我们真正的数据库操作了,本篇重点在于如何在网站端编写数据库操作语句,内容不多,就是我们常见的增删改查. 0.数据库对象创建: 在JAVASE基础知识总结时,就为大家 ...

  10. PL/SQL概念

    一. 为什么把SQL语句组合成PL/SQL语句块效率会更高? 使用PL/SQL语句块中的SQL语句更加高效,原因主要是这样做可以大幅降低网络流量,应用程序也会变得更加高效. 当客户端计算机发出一条SQ ...