Scalaz(5)- typeclass:my typeclass scalaz style-demo

  我们在上一篇讨论中介绍了一些基本的由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行为)

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

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

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

1 object NonZero {
2     def create[A](f: A => Boolean): NonZero[A] = new NonZero[A] {
3         def nonZero(a: A): Boolean = f(a)
4     }
5 }

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

下一步是注入操作方法:

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

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

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

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

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

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

1 object NonZero {
2     def create[A](f: A => Boolean): NonZero[A] = new NonZero[A] {
3         def nonZero(a: A): Boolean = f(a)
4     }
5     implicit val intNZInstance: NonZero[Int] = create {
6         case 0 => false
7         case _ => true
8      }
9 }

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

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

1 import ToNonZeroOps._
2 
3 10.isNonZero                                      //> res0: Boolean = true
4 0.isNonZero                                       //> res1: Boolean = false
5 2.isNonZero                                       //> res2: Boolean = true

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

 1 import ToNonZeroOps._
 2 implicit val stringNZInstance: NonZero[String] = NonZero.create {
 3   case "" => false
 4   case _ => true
 5 }                                                 //> stringNZInstance  : scalaz.ex5.NonZero[String] = scalaz.ex5$NonZero$$anon$1@
 6                                                   //| 1c655221
 7 implicit val booleanNZInstance: NonZero[Boolean] = NonZero.create { b => b }
 8                                                   //> booleanNZInstance  : scalaz.ex5.NonZero[Boolean] = scalaz.ex5$NonZero$$anon$
 9                                                   //| 1@6aaa5eb0
10 
11 implicit def listNZInstance[A]: NonZero[List[A]] = NonZero.create {
12     case Nil => false
13     case _ => true
14 }                                                 //> listNZInstance: [A]=> scalaz.ex5.NonZero[List[A]]
15 
16 "".isNonZero                                      //> res0: Boolean = false
17 "not empty".isNonZero                             //> res1: Boolean = true
18 true.isNonZero                                    //> res2: Boolean = true
19 false.isNonZero                                   //> res3: Boolean = false
20 List(1,2,3).isNonZero                             //> res4: Boolean = true
21 List("a","b").isNonZero                           //> res5: Boolean = true
22 List().isNonZero                                  //> res6: Boolean = false
23 
24 
25 
26 10.isNonZero                                      //> res7: Boolean = true
27 0.isNonZero                                       //> res8: Boolean = false
28 2.isNonZero                                       //> res9: Boolean = true

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

 1 trait NonZero[A] {
 2     def nonZero(a: A): Boolean
 3 }
 4 object NonZero {
 5     def create[A](f: A => Boolean): NonZero[A] = new NonZero[A] {
 6         def nonZero(a: A): Boolean = f(a)
 7     }
 8     implicit val intNZInstance: NonZero[Int] = create {
 9         case 0 => false
10         case _ => true
11      }
12 }
13 class NonZeroOps[A](a: A)(implicit ev: NonZero[A]) {
14     def isNonZero: Boolean = ev.nonZero(a)
15 }
16 object ToNonZeroOps {
17     implicit def toNonZeroOps[A](a: A)(implicit ev: NonZero[A]) = new NonZeroOps[A](a)
18 }
19 
20 import ToNonZeroOps._
21 implicit val stringNZInstance: NonZero[String] = NonZero.create {
22   case "" => false
23   case _ => true
24 }                                                 //> stringNZInstance  : scalaz.ex5.NonZero[String] = scalaz.ex5$NonZero$$anon$1@
25                                                   //| 1c655221
26 implicit val booleanNZInstance: NonZero[Boolean] = NonZero.create { b => b }
27                                                   //> booleanNZInstance  : scalaz.ex5.NonZero[Boolean] = scalaz.ex5$NonZero$$anon$
28                                                   //| 1@6aaa5eb0
29 
30 implicit def listNZInstance[A]: NonZero[List[A]] = NonZero.create {
31     case Nil => false
32     case _ => true
33 }                                                 //> listNZInstance: [A]=> scalaz.ex5.NonZero[List[A]]
34 
35 "".isNonZero                                      //> res0: Boolean = false
36 "not empty".isNonZero                             //> res1: Boolean = true
37 true.isNonZero                                    //> res2: Boolean = true
38 false.isNonZero                                   //> res3: Boolean = false
39 List(1,2,3).isNonZero                             //> res4: Boolean = true
40 List("a","b").isNonZero                           //> res5: Boolean = true
41 List().isNonZero                                  //> res6: Boolean = false
42 
43 
44 
45 10.isNonZero                                      //> res7: Boolean = true
46 0.isNonZero                                       //> res8: Boolean = false
47 2.isNonZero                                       //> res9: Boolean = true

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java一日一条

一个以前没有注意的问题:java构造函数的执行顺序

昨天在改一处代码时发现执行的过程和预想的不一样,仔细探究才发现是构造器执行顺序问题.(汗自己一下,基础不够扎实) 特地做了一些尝试然后把java构造器的执行顺...

421
来自专栏阮一峰的网络日志

JavaScript 有多灵活?

JavaScript 是一种灵活的语言,表达力极强,我来举一个例子,保证让很多人大吃一惊。 本文受到了 Kyle Simpson 的文章《Iterating E...

3187
来自专栏坚毅的PHP

list comprehensions

2011-10-07 列表解析 python很优雅的东西,今天从cookbook稍微深的理解下它,举例: >>> multi = [[0] * 5] * 3 ...

3293
来自专栏专注 Java 基础分享

详解Java API之正则表达式

     正则表达式描述的是一种规则,符合这种限定规则的字符串我们认为它某种满足条件的,是我们所需的。在正则表达式中,主要有两种字符,一种描述的是普通的字符,另...

1889
来自专栏有趣的django

5.python函数

函数介绍 定义:  函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可。 特性:减少重复代码、使程序变的可扩展、使程...

2566
来自专栏C/C++基础

C++学习知识点

答:多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。 C++中,实现多态有...

562
来自专栏Python爱好者

Java基础笔记04

1545
来自专栏程序员互动联盟

【java基础】static关键字--修饰静态变量

在我们平时的使用当中,static最常用的功能就是修饰类的属性和方法,让他们成为类的成员属性和方法,我们通常将用static修饰的成员称为类成员或者静态成员,这...

3124
来自专栏码云1024

JAVA 第二天 关键字

2607
来自专栏梧雨北辰的开发录

Swift学习:构造器(中)

本篇继续对Swift中的构造器进行介绍,这里主要说到类的继承和构造。 作为引用类型的类具有的继承特性,这使得类的构造过程较为复杂一些,因为涉及到很多细节性的问题...

2958

扫码关注云+社区