在前几篇关于Functor和Applilcative typeclass的讨论中我们自定义了一个类型Configure,Configure类型的定义是这样的:

 1 case class Configure[+A](get: A)
 2 object Configure {
 3     implicit val configFunctor = new Functor[Configure] {
 4         def map[A,B](ca: Configure[A])(f: A => B): Configure[B] = Configure(f(ca.get))
 5     }
 6     implicit val configApplicative = new Applicative[Configure] {
 7         def point[A](a: => A) = Configure(a)
 8         def ap[A,B](ca: => Configure[A])(cfab: => Configure[A => B]): Configure[B] = cfab map {fab => fab(ca.get)}
 9     }
10 }

通过定义了Configure类型的Functor和Applicative隐式实例(implicit instance),我们希望Configure类型既是一个Functor也是一个Applicative。那么怎么才能证明这个说法呢?我们只要证明Configure类型的实例能遵循它所代表的typeclass操作定律就行了。Scalaz为大部分typeclass提供了测试程序(scalacheck properties)。在scalaz/scalacheck-binding/src/main/scala/scalaz/scalacheck/scalazProperties.scala里我们可以发现有关functor scalacheck properties:

 1 object functor {
 2     def identity[F[_], X](implicit F: Functor[F], afx: Arbitrary[F[X]], ef: Equal[F[X]]) =
 3       forAll(F.functorLaw.identity[X] _)
 4
 5     def composite[F[_], X, Y, Z](implicit F: Functor[F], af: Arbitrary[F[X]], axy: Arbitrary[(X => Y)],
 6                                    ayz: Arbitrary[(Y => Z)], ef: Equal[F[Z]]) =
 7       forAll(F.functorLaw.composite[X, Y, Z] _)
 8
 9     def laws[F[_]](implicit F: Functor[F], af: Arbitrary[F[Int]], axy: Arbitrary[(Int => Int)],
10                    ef: Equal[F[Int]]) = new Properties("functor") {
11       include(invariantFunctor.laws[F])
12       property("identity") = identity[F, Int]
13       property("composite") = composite[F, Int, Int, Int]
14     }
15   }

可以看到:functor.laws[F[_]]主要测试了identity, composite及invariantFunctor的properties。在scalaz/Functor.scala文件中定义了这几条定律:

 1  trait FunctorLaw extends InvariantFunctorLaw {
 2     /** The identity function, lifted, is a no-op. */
 3     def identity[A](fa: F[A])(implicit FA: Equal[F[A]]): Boolean = FA.equal(map(fa)(x => x), fa)
 4
 5     /**
 6      * A series of maps may be freely rewritten as a single map on a
 7      * composed function.
 8      */
 9     def composite[A, B, C](fa: F[A], f1: A => B, f2: B => C)(implicit FC: Equal[F[C]]): Boolean = FC.equal(map(map(fa)(f1))(f2), map(fa)(f2 compose f1))
10   }
11  。

我们在下面试着对那个Configure类型进行Functor实例和Applicative实例的测试:

 1 import scalaz._
 2 import Scalaz._
 3 import shapeless._
 4 import scalacheck.ScalazProperties._
 5 import scalacheck.ScalazArbitrary._
 6 import scalacheck.ScalaCheckBinding._
 7 import org.scalacheck.{Gen, Arbitrary}
 8 implicit def cofigEqual[A]: Equal[Configure[A]] = Equal.equalA
 9                                                   //> cofigEqual: [A#2921073]=> scalaz#31.Equal#41646[Exercises#29.ex1#59011.Confi
10                                                   //| gure#2921067[A#2921073]]
11 implicit def configArbi[A](implicit a: Arbitrary[A]): Arbitrary[Configure[A]] =
12    a map { b => Configure(b) }                    //> configArbi: [A#2921076](implicit a#2921242: org#15.scalacheck#121951.Arbitra
13                                                   //| ry#122597[A#2921076])org#15.scalacheck#121951.Arbitrary#122597[Exercises#29.
14                                                   //| ex1#59011.Configure#2921067[A#2921076]]

除了需要的import外还必须定义Configure类型的Equal实例以及任意测试数据产生器(test data generator)configArbi[A]。我们先测试Functor属性:

1 functor.laws[Configure].check                     //>
2 + functor.invariantFunctor.identity: OK, passed 100 tests.
3                                                   //|
4 + functor.invariantFunctor.composite: OK, passed 100 tests.
5                                                   //|
6 + functor.identity: OK, passed 100 tests.
7                                                   //|
8 + functor.composite: OK, passed 100 tests.

成功通过Functor定律测试。

再看看Applicative的scalacheck property:scalaz/scalacheck/scalazProperties.scala

 1  object applicative {
 2     def identity[F[_], X](implicit f: Applicative[F], afx: Arbitrary[F[X]], ef: Equal[F[X]]) =
 3       forAll(f.applicativeLaw.identityAp[X] _)
 4
 5     def homomorphism[F[_], X, Y](implicit ap: Applicative[F], ax: Arbitrary[X], af: Arbitrary[X => Y], e: Equal[F[Y]]) =
 6       forAll(ap.applicativeLaw.homomorphism[X, Y] _)
 7
 8     def interchange[F[_], X, Y](implicit ap: Applicative[F], ax: Arbitrary[X], afx: Arbitrary[F[X => Y]], e: Equal[F[Y]]) =
 9       forAll(ap.applicativeLaw.interchange[X, Y] _)
10
11     def mapApConsistency[F[_], X, Y](implicit ap: Applicative[F], ax: Arbitrary[F[X]], afx: Arbitrary[X => Y], e: Equal[F[Y]]) =
12       forAll(ap.applicativeLaw.mapLikeDerived[X, Y] _)
13
14     def laws[F[_]](implicit F: Applicative[F], af: Arbitrary[F[Int]],
15                    aff: Arbitrary[F[Int => Int]], e: Equal[F[Int]]) = new Properties("applicative") {
16       include(ScalazProperties.apply.laws[F])
17       property("identity") = applicative.identity[F, Int]
18       property("homomorphism") = applicative.homomorphism[F, Int, Int]
19       property("interchange") = applicative.interchange[F, Int, Int]
20       property("map consistent with ap") = applicative.mapApConsistency[F, Int, Int]
21     }
22   }

applicative.laws定义了4个测试Property再加上apply的测试property。这些定律(laws)在scalaz/Applicative.scala里定义了:

 1  trait ApplicativeLaw extends ApplyLaw {
 2     /** `point(identity)` is a no-op. */
 3     def identityAp[A](fa: F[A])(implicit FA: Equal[F[A]]): Boolean =
 4       FA.equal(ap(fa)(point((a: A) => a)), fa)
 5
 6     /** `point` distributes over function applications. */
 7     def homomorphism[A, B](ab: A => B, a: A)(implicit FB: Equal[F[B]]): Boolean =
 8       FB.equal(ap(point(a))(point(ab)), point(ab(a)))
 9
10     /** `point` is a left and right identity, F-wise. */
11     def interchange[A, B](f: F[A => B], a: A)(implicit FB: Equal[F[B]]): Boolean =
12       FB.equal(ap(point(a))(f), ap(f)(point((f: A => B) => f(a))))
13
14     /** `map` is like the one derived from `point` and `ap`. */
15     def mapLikeDerived[A, B](f: A => B, fa: F[A])(implicit FB: Equal[F[B]]): Boolean =
16       FB.equal(map(fa)(f), ap(fa)(point(f)))
17   }

再测试一下Configure类型是否也遵循Applicative定律:

 1 pplicative.laws[Configure].check                 //>
 2 + applicative.apply.functor.invariantFunctor.identity: OK, passed 100 tests
 3                                                   //|
 4                                                   //|   .
 5                                                   //|
 6 + applicative.apply.functor.invariantFunctor.composite: OK, passed 100 test
 7                                                   //|
 8                                                   //|   s.
 9                                                   //|
10 + applicative.apply.functor.identity: OK, passed 100 tests.
11                                                   //|
12 + applicative.apply.functor.composite: OK, passed 100 tests.
13                                                   //|
14 + applicative.apply.composition: OK, passed 100 tests.
15                                                   //|
16 + applicative.identity: OK, passed 100 tests.
17                                                   //|
18 + applicative.homomorphism: OK, passed 100 tests.
19                                                   //|
20 + applicative.interchange: OK, passed 100 tests.
21                                                   //|
22 + applicative.map consistent with ap: OK, passed 100 tests.

功通过了Applicative定律测试。现在我们可以说Configure类型既是Functor也是Applicative。

转载于:https://www.cnblogs.com/tiger-xc/p/4875649.html

Scalaz(9)- typeclass:checking instance abiding the laws相关推荐

  1. Scalaz(7)- typeclass:Applicative-idomatic function application

    Applicative,正如它的名称所示,就是FP模式的函数施用(function application).我们在前面的讨论中不断提到FP模式的操作一般都在管道里进行的,因为FP的变量表达形式是这样 ...

  2. Scalaz(25)- Monad: Monad Transformer-叠加Monad效果

    中间插播了几篇scalaz数据类型,现在又要回到Monad专题.因为FP的特征就是Monad式编程(Monadic programming),所以必须充分理解认识Monad.熟练掌握Monad运用.曾 ...

  3. Scalaz(12)- Monad:再述述flatMap,顺便了解MonadPlus

    在前面的几篇讨论里我们初步对FP有了些少了解:FP嘛,不就是F[A]吗?也是,FP就是在F[]壳子(context)内对程序的状态进行更改,也就是在F壳子(context)内施用一些函数.再直白一点就 ...

  4. Scalaz(44)- concurrency :scalaz Future,尚不完整的多线程类型

    scala已经配备了自身的Future类.我们先举个例子来了解scala Future的具体操作: 1 import scala.concurrent._ 2 import ExecutionCont ...

  5. Scalaz(38)- Free :Coproduct-Monadic语句组合

    很多函数式编程爱好者都把FP称为Monadic Programming,意思是用Monad进行编程.我想FP作为一种比较成熟的编程模式,应该有一套比较规范的操作模式吧.因为Free能把任何F[A]升格 ...

  6. Scalaz(32)- Free :lift - Monad生产线

    在前面的讨论里我们提到自由数据结构就是产生某种类型的最简化结构,比如:free monoid, free monad, free category等等.我们也证明了List[A]是个free mono ...

  7. Scalaz(23)- 泛函数据结构: Zipper-游标定位

    外面沙尘滚滚一直向北去了,意识到年关到了,码农们都回乡过年去了,而我却留在这里玩弄"拉链".不要想歪了,我说的不是裤裆拉链而是scalaz Zipper,一种泛函数据结构游标(cu ...

  8. Scalaz(1)- 基础篇:隐式转换解析策略-Implicit resolution

    在正式进入scalaz讨论前我们需要理顺一些基础的scalaz结构组成概念和技巧.scalaz是由即兴多态(ad-hoc polymorphism)类型(typeclass)组成.scalaz typ ...

  9. Scalaz(21)-类型例证:Liskov and Leibniz - type evidence

    Leskov,Leibniz,别扭的名字,是什么地干活?碰巧从scalaz源代码里发现了这么个东西:scalaz/BindSyntax.scala /** Wraps a value `self` a ...

最新文章

  1. leetcode算法题--最长字符串链
  2. C语言,获得堆栈增长方向的一种方法
  3. Java获得随机数字
  4. QQ 互联审核不通过问题的解决方法
  5. mfc如何将一个数组中的字节数据用串口发送出去_RS232串口多机通信
  6. 【IE6的疯狂之四】IE6文字溢出BUG
  7. 进程控制块PCB(进程描述符)
  8. vs2013编译osg缺少mfc120d.lib
  9. android 剩余,关于android:android-剩余部分
  10. AutoCompleteTextView组件的功能和用法
  11. linux既能归档也能压缩的命令,Linux压缩及归档
  12. 简述mysql事件作用_MYSQL使用简述
  13. div探索系列(二):让多个div显示在一行(浮动的div)
  14. 【BZOJ 3652】大新闻 数位dp+期望概率dp
  15. 【转】keil5 missing close quote 错误解决
  16. 【高等数学】多元函数f(x,y...)的泰勒(Taylor)展开式
  17. PyTorch安装及试用 基于Anaconda3
  18. mysql复合索引加锁_Mysql加锁过程详解
  19. 什么是负载?如何查看服务器的机器负载情况?
  20. 南宁第一职业技术学校计算机专业,南宁第一职业技术学校

热门文章

  1. JVM调优:-XX:+UseConcMarkSweepGC 使用CMS垃圾回收器
  2. Linux traceroute路由跟踪
  3. IDEA的查询引用、调用关系图的功能
  4. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(五)
  5. python 去掉list元素的双引号_一天快速入门 Python
  6. 2013NOIP普级组-- 小朋友的数字
  7. html外边距的复合属性是,margin
  8. eventbus使用_Android EventBus框架的使用介绍
  9. 时序图 分支_BOOM微架构学习(1)——取指单元与分支预测
  10. python3安装setuptools步骤_linux环境下的python安装过程(含setuptools)