Scalaz(9)- typeclass:checking instance abiding the laws
来源:互联网 发布:汇编语言编程软件 编辑:程序博客网 时间:2024/06/05 13:22
在前几篇关于Functor和Applilcative typeclass的讨论中我们自定义了一个类型Configure,Configure类型的定义是这样的:
case class Configure[+A](get: A)object Configure { implicit val configFunctor = new Functor[Configure] { def map[A,B](ca: Configure[A])(f: A => B): Configure[B] = Configure(f(ca.get)) } implicit val configApplicative = new Applicative[Configure] { def point[A](a: => A) = Configure(a) def ap[A,B](ca: => Configure[A])(cfab: => Configure[A => B]): Configure[B] = cfab map {fab => fab(ca.get)} }}
通过定义了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:
object functor { def identity[F[_], X](implicit F: Functor[F], afx: Arbitrary[F[X]], ef: Equal[F[X]]) = forAll(F.functorLaw.identity[X] _) def composite[F[_], X, Y, Z](implicit F: Functor[F], af: Arbitrary[F[X]], axy: Arbitrary[(X => Y)], ayz: Arbitrary[(Y => Z)], ef: Equal[F[Z]]) = forAll(F.functorLaw.composite[X, Y, Z] _) def laws[F[_]](implicit F: Functor[F], af: Arbitrary[F[Int]], axy: Arbitrary[(Int => Int)], ef: Equal[F[Int]]) = new Properties("functor") { include(invariantFunctor.laws[F]) property("identity") = identity[F, Int] property("composite") = composite[F, Int, Int, Int] } }
可以看到:functor.laws[F[_]]主要测试了identity, composite及invariantFunctor的properties。在scalaz/Functor.scala文件中定义了这几条定律:
trait FunctorLaw extends InvariantFunctorLaw { /** The identity function, lifted, is a no-op. */ def identity[A](fa: F[A])(implicit FA: Equal[F[A]]): Boolean = FA.equal(map(fa)(x => x), fa) /** * A series of maps may be freely rewritten as a single map on a * composed function. */ 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)) } 。。。
我们在下面试着对那个Configure类型进行Functor实例和Applicative实例的测试:
import scalaz._import Scalaz._import shapeless._import scalacheck.ScalazProperties._import scalacheck.ScalazArbitrary._import scalacheck.ScalaCheckBinding._import org.scalacheck.{Gen, Arbitrary}implicit def cofigEqual[A]: Equal[Configure[A]] = Equal.equalA //> cofigEqual: [A#2921073]=> scalaz#31.Equal#41646[Exercises#29.ex1#59011.Confi //| gure#2921067[A#2921073]]implicit def configArbi[A](implicit a: Arbitrary[A]): Arbitrary[Configure[A]] = a map { b => Configure(b) } //> configArbi: [A#2921076](implicit a#2921242: org#15.scalacheck#121951.Arbitra //| ry#122597[A#2921076])org#15.scalacheck#121951.Arbitrary#122597[Exercises#29. //| ex1#59011.Configure#2921067[A#2921076]]
除了需要的import外还必须定义Configure类型的Equal实例以及任意测试数据产生器(test data generator)configArbi[A]。我们先测试Functor属性:
functor.laws[Configure].check //> + functor.invariantFunctor.identity: OK, passed 100 tests. //| + functor.invariantFunctor.composite: OK, passed 100 tests. //| + functor.identity: OK, passed 100 tests. //| + functor.composite: OK, passed 100 tests.
成功通过Functor定律测试。
再看看Applicative的scalacheck property:scalaz/scalacheck/scalazProperties.scala
object applicative { def identity[F[_], X](implicit f: Applicative[F], afx: Arbitrary[F[X]], ef: Equal[F[X]]) = forAll(f.applicativeLaw.identityAp[X] _) def homomorphism[F[_], X, Y](implicit ap: Applicative[F], ax: Arbitrary[X], af: Arbitrary[X => Y], e: Equal[F[Y]]) = forAll(ap.applicativeLaw.homomorphism[X, Y] _) def interchange[F[_], X, Y](implicit ap: Applicative[F], ax: Arbitrary[X], afx: Arbitrary[F[X => Y]], e: Equal[F[Y]]) = forAll(ap.applicativeLaw.interchange[X, Y] _) def mapApConsistency[F[_], X, Y](implicit ap: Applicative[F], ax: Arbitrary[F[X]], afx: Arbitrary[X => Y], e: Equal[F[Y]]) = forAll(ap.applicativeLaw.mapLikeDerived[X, Y] _) def laws[F[_]](implicit F: Applicative[F], af: Arbitrary[F[Int]], aff: Arbitrary[F[Int => Int]], e: Equal[F[Int]]) = new Properties("applicative") { include(ScalazProperties.apply.laws[F]) property("identity") = applicative.identity[F, Int] property("homomorphism") = applicative.homomorphism[F, Int, Int] property("interchange") = applicative.interchange[F, Int, Int] property("map consistent with ap") = applicative.mapApConsistency[F, Int, Int] } }
applicative.laws定义了4个测试Property再加上apply的测试property。这些定律(laws)在scalaz/Applicative.scala里定义了:
trait ApplicativeLaw extends ApplyLaw { /** `point(identity)` is a no-op. */ def identityAp[A](fa: F[A])(implicit FA: Equal[F[A]]): Boolean = FA.equal(ap(fa)(point((a: A) => a)), fa) /** `point` distributes over function applications. */ def homomorphism[A, B](ab: A => B, a: A)(implicit FB: Equal[F[B]]): Boolean = FB.equal(ap(point(a))(point(ab)), point(ab(a))) /** `point` is a left and right identity, F-wise. */ def interchange[A, B](f: F[A => B], a: A)(implicit FB: Equal[F[B]]): Boolean = FB.equal(ap(point(a))(f), ap(f)(point((f: A => B) => f(a)))) /** `map` is like the one derived from `point` and `ap`. */ def mapLikeDerived[A, B](f: A => B, fa: F[A])(implicit FB: Equal[F[B]]): Boolean = FB.equal(map(fa)(f), ap(fa)(point(f))) }
再测试一下Configure类型是否也遵循Applicative定律:
applicative.laws[Configure].check //> + applicative.apply.functor.invariantFunctor.identity: OK, passed 100 tests //| //| . //| + applicative.apply.functor.invariantFunctor.composite: OK, passed 100 test //| //| s. //| + applicative.apply.functor.identity: OK, passed 100 tests. //| + applicative.apply.functor.composite: OK, passed 100 tests. //| + applicative.apply.composition: OK, passed 100 tests. //| + applicative.identity: OK, passed 100 tests. //| + applicative.homomorphism: OK, passed 100 tests. //| + applicative.interchange: OK, passed 100 tests. //| + applicative.map consistent with ap: OK, passed 100 tests.
成功通过了Applicative定律测试。现在我们可以说Configure类型既是Functor也是Applicative。
- Scalaz(9)- typeclass:checking instance abiding the laws
- Scalaz(5)- typeclass:my typeclass scalaz style-demo
- Scalaz(6)- typeclass:Functor-just map
- Scalaz(7)- typeclass:Applicative-idomatic function application
- Scalaz(8)- typeclass:Monoid and Foldable
- Scalaz(2)- 基础篇:随意多态-typeclass, ad-hoc polymorphism
- Scalaz(4)- typeclass:标准类型-Equal,Order,Show,Enum
- Scalaz(46)- scalaz-stream 基础介绍
- Scalaz(47)- scalaz-stream: 深入了解-Source
- Scalaz(49)- scalaz-stream: 深入了解-Sink/Channel
- Golang的反射机制(The Laws of Reflection)
- Scalaz(50)- scalaz-stream: 安全的无穷运算-running infinite stream freely
- Scalaz(51)- scalaz-stream: 资源使用安全-Resource Safety
- Scalaz(52)- scalaz-stream: 并行运算-parallel processing concurrently by merging
- Scalaz(53)- scalaz-stream: 程序运算器-application scenario
- Scalaz(54)- scalaz-stream: 函数式多线程编程模式-Free Streaming Programming Model
- Scalaz(44)- concurrency :scalaz Future,尚不完整的多线程类型
- Scalaz(48)- scalaz-stream: 深入了解-Transducer: Process1-tee-wye
- Http中Get/Post请求区别
- n皇后问题
- Cg shader using additive blending
- 抽象的(abstract)方法 是否可同时是 静态的(static),是否可同时是 本地方法(native),是否可同时被 synchronized修饰?
- 单例模式
- Scalaz(9)- typeclass:checking instance abiding the laws
- openstack从零开始(2)——基础知识openstack中消息通信
- 【Oracle】新创建用户时,授予Connect和Resouce权限报ORA-01045 错误
- JAVA项目开发包环境部署
- 哈密尔顿回路问题
- C语言课
- BZOJ1045 糖果传递
- WebService、soap、gsoap基本概念
- Sae中mysql的初步使用