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放一个默认隐式转换:


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 0 => false
        case _ => true
     }
}

注意我们在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

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


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(1,2,3).isNonZero                             //> res4: Boolean = true
List("a","b").isNonZero                           //> res5: Boolean = true
List().isNonZero                                  //> res6: Boolean = false



10.isNonZero                                      //> res7: Boolean = true
0.isNonZero                                       //> res8: Boolean = false
2.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 0 => 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(1,2,3).isNonZero                             //> res4: Boolean = true
List("a","b").isNonZero                           //> res5: Boolean = true
List().isNonZero                                  //> res6: Boolean = false



10.isNonZero                                      //> res7: Boolean = true
0.isNonZero                                       //> res8: Boolean = false
2.isNonZero                                       //> res9: Boolean = true


相关文章
|
5月前
|
开发工具 git
Stylelint—— Expected class selector ".nut-popup--top" to be kebab-case selector-class-pattern
新项目制定规范接入了stylelint,并通过husky在git提交时去触发检测修复,因为使用的是NutUi,所以无法直接调整组件对应的类名称,只好在stylelint.config.js中加入相应的rules进行配置。
151 0
03HUI -基础文本(hui-common-title)
03HUI -基础文本(hui-common-title)
62 0
|
8月前
|
CDN
highlight demo
highlight demo
40 0
|
Android开发
<interface declaration>, <parcelable declaration>, AidlTokenType.import or AidlTokenType.package ...
<interface declaration>, <parcelable declaration>, AidlTokenType.import or AidlTokenType.package ...
90 0
<interface declaration>, <parcelable declaration>, AidlTokenType.import or AidlTokenType.package ...
|
缓存 程序员 编译器
译|There Are No Reference Types in Go
译|There Are No Reference Types in Go
81 0
|
Android开发
Failed to transform artifact 'butterknife-runtime.aar (com.jakewharton:butterknife-runtime:10.1.0)'
Failed to transform artifact 'butterknife-runtime.aar (com.jakewharton:butterknife-runtime:10.1.0)'
|
Dart 编译器
Functions Paramaters——Dart
Dart是一个完全面向对象的语言,它的方法也是对象,对应的类型为Function。 这意味着方法也能被赋值给变量,或者当做参数传递给其他方法。
|
前端开发 .NET Linux
Nancy之基于Nancy.Hosting.Aspnet的小Demo
原文:Nancy之基于Nancy.Hosting.Aspnet的小Demo 近来学习了一下Nancy这个框架,感觉挺好用的,就写篇简单的文章记录一下大致用法,由于是刚接触,写的代码 可能不规范,也没有具体的分层。
1408 0
|
Android开发 Spring
An internal error occurred during: &quot;Building UI model&quot;. com/google/common/base/Function
An internal error occurred during: "Building UI model". com/google/common/base/FunctionEclipse Neon.2 Release (4.6.2) 安装了 STS(Spring Tool Suite) 后,创建项目时遇到些问题。
2760 0

热门文章

最新文章