Scalaz(9)- typeclass:checking instance abiding the laws
? 在前幾篇關于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的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 两个u盘 一个能用一个识别不出来怎么办
- 下一篇: 关于KVM的几篇细节文档