|
1 | 1 | package scalaz
|
2 | 2 |
|
3 |
| -import scalaz.scalacheck.ScalazProperties |
4 |
| -import scalaz.scalacheck.ScalazProperties._ |
5 |
| -import scalaz.scalacheck.ScalazArbitrary._ |
6 |
| -import scalaz.scalacheck.ScalaCheckBinding._ |
7 |
| -import std.AllInstances._ |
8 |
| -import org.scalacheck.{Arbitrary, Cogen} |
9 |
| -import org.scalacheck.Prop.forAll |
10 |
| -import Cofree._ |
11 |
| -import Cofree.CofreeZip |
12 |
| -import Isomorphism._ |
| 3 | +import scalaz.std.anyVal._ |
| 4 | +import scalaz.std.list._ |
| 5 | +import scalaz.std.java.enum._ |
13 | 6 |
|
14 |
| -object CofreeTest extends SpecLite { |
| 7 | +object CofreeTest { |
15 | 8 |
|
16 |
| - type CofreeLazyOption[A] = Cofree[LazyOption, A] |
17 |
| - type CofreeStream[A] = Cofree[Stream, A] |
18 |
| - type OneAndStream[A] = OneAnd[Stream, A] |
19 |
| - type OneAndList[A] = OneAnd[List, A] |
20 |
| - type CofreeOption[A] = Cofree[Option, A] |
| 9 | + implicitly[Equal[Cofree[List, Int]]] |
21 | 10 |
|
22 |
| - implicit def cofreeEqual[F[_], A](implicit F: Eq1[F], A: Equal[A]): Equal[Cofree[F, A]] = |
23 |
| - Equal.equal{ (a, b) => |
24 |
| - A.equal(a.head, b.head) && F.eq1(cofreeEqual[F, A]).equal(a.tail, b.tail) |
25 |
| - } |
26 |
| - |
27 |
| - implicit def cofreeZipEqual[F[_]: Eq1, A: Equal]: Equal[CofreeZip[F, A]] = |
28 |
| - Tag.subst(cofreeEqual[F, A]) |
29 |
| - |
30 |
| - //needed to prevent SOE for testing with equality |
31 |
| - implicit def cofreeOptEquals[A](implicit e: Equal[A]): Equal[CofreeOption[A]] = new Equal[CofreeOption[A]] { |
32 |
| - override def equal(a: CofreeOption[A], b: CofreeOption[A]): Boolean = { |
33 |
| - def tr(a: CofreeOption[A], b: CofreeOption[A]): Boolean = |
34 |
| - (a.tail, b.tail) match { |
35 |
| - case (Some(at), Some(bt)) if (e.equal(a.head, b.head)) => tr(at, bt) |
36 |
| - case (None, None) if (e.equal(a.head, b.head)) => true |
37 |
| - case _ => false |
38 |
| - } |
39 |
| - tr(a,b) |
40 |
| - } |
41 |
| - } |
42 |
| - |
43 |
| - val oneAndListCofreeOptionIso: OneAndList <~> CofreeOption = |
44 |
| - new IsoFunctorTemplate[OneAndList, CofreeOption] { |
45 |
| - def to[A](fa: OneAndList[A]) = |
46 |
| - Cofree.unfold(fa) { |
47 |
| - case OneAnd(a, h :: t) => |
48 |
| - (a, Some(OneAnd(h, t))) |
49 |
| - case OneAnd(a, _) => (a, None) |
50 |
| - } |
51 |
| - def from[A](ga: CofreeOption[A]) = |
52 |
| - OneAnd( |
53 |
| - ga.head, |
54 |
| - ga.tail.map(s => |
55 |
| - Foldable[CofreeOption].foldRight(s, List.empty[A])(_ :: _) |
56 |
| - ).getOrElse(Nil) |
57 |
| - ) |
58 |
| - } |
59 |
| - |
60 |
| - val oneAndStreamCofreeLazyOptionIso: OneAndStream <~> CofreeLazyOption = |
61 |
| - new IsoFunctorTemplate[OneAndStream, CofreeLazyOption] { |
62 |
| - def to[A](fa: OneAndStream[A]) = |
63 |
| - Cofree.unfold(fa){ |
64 |
| - case OneAnd(a, h #:: t) => (a, LazyOption.lazySome(OneAnd(h, t))) |
65 |
| - case OneAnd(a, _) => (a, LazyOption.lazyNone) |
66 |
| - } |
67 |
| - def from[A](fa: CofreeLazyOption[A]) = |
68 |
| - OneAnd( |
69 |
| - fa.head, |
70 |
| - fa.tail.map(s => |
71 |
| - Foldable[CofreeLazyOption].foldRight(s, Stream.empty[A])(_ #:: _) |
72 |
| - ).getOrElse(Stream.empty) |
73 |
| - ) |
74 |
| - } |
75 |
| - |
76 |
| - val treeCofreeStreamIso: Tree <~> CofreeStream = |
77 |
| - new IsoFunctorTemplate[Tree, CofreeStream] { |
78 |
| - def to[A](tree: Tree[A]): CofreeStream[A] = |
79 |
| - Cofree(tree.rootLabel, tree.subForest.map(to(_))) |
80 |
| - def from[A](c: CofreeStream[A]): Tree[A] = |
81 |
| - Tree.Node(c.head, c.tail.map(from(_))) |
82 |
| - } |
83 |
| - |
84 |
| - implicit def CofreeLazyOptionArb[A: Arbitrary]: Arbitrary[CofreeLazyOption[A]] = |
85 |
| - Functor[Arbitrary].map(implicitly[Arbitrary[OneAndStream[A]]])(oneAndStreamCofreeLazyOptionIso.to(_)) |
86 |
| - |
87 |
| - implicit def CofreeStreamArb[A: Arbitrary]: Arbitrary[CofreeStream[A]] = |
88 |
| - Functor[Arbitrary].map(implicitly[Arbitrary[Tree[A]]])(treeCofreeStreamIso.to.apply) |
89 |
| - |
90 |
| - implicit def CofreeLazyOptionCogen[A: Cogen]: Cogen[CofreeLazyOption[A]] = |
91 |
| - implicitly[Cogen[OneAndStream[A]]].contramap(oneAndStreamCofreeLazyOptionIso.from.apply) |
92 |
| - |
93 |
| - implicit def CofreeStreamCogen[A: Cogen]: Cogen[CofreeStream[A]] = |
94 |
| - implicitly[Cogen[Tree[A]]].contramap(treeCofreeStreamIso.from.apply) |
95 |
| - |
96 |
| - implicit def CofreeOptionCogen[A: Cogen]: Cogen[CofreeOption[A]] = |
97 |
| - implicitly[Cogen[OneAndList[A]]].contramap(oneAndListCofreeOptionIso.from.apply) |
98 |
| - |
99 |
| - implicit def CofreeOptionArb[A: Arbitrary]: Arbitrary[CofreeOption[A]] = { |
100 |
| - import org.scalacheck.Arbitrary._ |
101 |
| - import org.scalacheck.Gen |
102 |
| - val arb = Arbitrary { Gen.listOfN(20, implicitly[Arbitrary[A]].arbitrary ) } |
103 |
| - Functor[Arbitrary].map(arb){ |
104 |
| - case h :: Nil => oneAndListCofreeOptionIso.to( OneAnd(h, Nil)) |
105 |
| - case h :: t => oneAndListCofreeOptionIso.to( OneAnd(h, t) ) |
106 |
| - } |
107 |
| - } |
108 |
| - |
109 |
| - checkAll("CofreeLazyOption", comonad.laws[CofreeLazyOption]) |
110 |
| - checkAll("CofreeLazyOption", traverse1.laws[CofreeLazyOption]) |
111 |
| - checkAll("CofreeLazyOption", monad.laws[CofreeLazyOption]) |
112 |
| - checkAll("CofreeLazyOption", equal.laws[CofreeLazyOption[Int]]) |
113 |
| - |
114 |
| - checkAll("CofreeStream", comonad.laws[CofreeStream]) |
115 |
| - checkAll("CofreeStream", traverse1.laws[CofreeStream]) |
116 |
| - checkAll("CofreeStream", monad.laws[CofreeStream]) |
117 |
| - checkAll("CofreeStream", equal.laws[CofreeStream[Int]]) |
118 |
| - |
119 |
| - checkAll("CofreeOption", comonad.laws[CofreeOption]) |
120 |
| - checkAll("CofreeOption", monad.laws[CofreeOption]) |
121 |
| - |
122 |
| - { |
123 |
| - type CofreeZipLazyOption[A] = CofreeZip[LazyOption, A] |
124 |
| - |
125 |
| - implicit def CofreeZipLazyOptionArb[A: Arbitrary]: Arbitrary[CofreeZipLazyOption[A]] = |
126 |
| - Tags.Zip.subst(CofreeLazyOptionArb[A]) |
127 |
| - |
128 |
| - // Hack: avoid stack overflow because `Applicative[CofreeLazyOption].point` is infinite stream |
129 |
| - def CofreeZipLazyOptionEqual[A: Equal]: Equal[CofreeZipLazyOption[A]] = |
130 |
| - Equal.equalBy{ a => |
131 |
| - val OneAnd(h, t) = oneAndStreamCofreeLazyOptionIso.from(Tag.unwrap(a)) |
132 |
| - h -> t.take(1000) |
133 |
| - } |
134 |
| - |
135 |
| - checkAll("CofreeZipLazyOption", applicative.laws[CofreeZipLazyOption](implicitly, implicitly, implicitly, CofreeZipLazyOptionEqual)) |
136 |
| - } |
137 |
| - |
138 |
| - { |
139 |
| - type CofreeZipStream[A] = CofreeZip[Stream, A] |
140 |
| - |
141 |
| - implicit def CofreeZipStreamArb[A: Arbitrary]: Arbitrary[CofreeZipStream[A]] = |
142 |
| - Tags.Zip.subst(CofreeStreamArb[A]) |
143 |
| - |
144 |
| - checkAll("CofreeZipStream", ScalazProperties.apply.laws[CofreeZipStream]) |
145 |
| - } |
146 |
| - |
147 |
| - "no stack overflow Applicative[CofreeZip[IList, ?]]#point" in { |
148 |
| - val a = 1 |
149 |
| - val b = Applicative[CofreeZip[IList, ?]].point(a) |
150 |
| - val size = 10 |
151 |
| - Foldable[Cofree[IList, ?]].toStream(Tag.unwrap(b)).take(size) must_=== Stream.fill(size)(a) |
152 |
| - } |
153 |
| - |
154 |
| - "Applicative[λ[α => CofreeZip[LazyOption, α]]] is Applicative[λ[α => Stream[α] @@ Zip]]" ! forAll{ |
155 |
| - (a: OneAndStream[Int], b: OneAndStream[Int]) => |
156 |
| - |
157 |
| - import syntax.foldable._ |
158 |
| - val f = (_: Int) + (_: Int) |
159 |
| - val h #:: t = Tag.unwrap(Applicative[λ[α => Stream[α] @@ Tags.Zip]].apply2(Tags.Zip[Stream[Int]](a.toStream), Tags.Zip[Stream[Int]](b.toStream))(f)) |
160 |
| - |
161 |
| - val aa = Tags.Zip(oneAndStreamCofreeLazyOptionIso.to(a)) |
162 |
| - val bb = Tags.Zip(oneAndStreamCofreeLazyOptionIso.to(b)) |
163 |
| - val y = Applicative[λ[α => CofreeZip[LazyOption, α]]].apply2(aa, bb)(f) |
164 |
| - OneAnd(h, t) must_=== oneAndStreamCofreeLazyOptionIso.from(Tag.unwrap(y)) |
165 |
| - } |
166 |
| - |
167 |
| - "no stack overflow unfoldC, mapBranching" in { |
168 |
| - import syntax.foldable._ |
169 |
| - val n = 100 |
170 |
| - val list = Cofree.unfoldC(1)(a => Option(a + 1)).mapBranching(NaturalTransformation.refl).toStream.take(n).toList |
171 |
| - list must_=== (1 to n).toList |
172 |
| - } |
173 |
| - |
174 |
| - object instances{ |
175 |
| - def comonad[F[_]: Functor] = Comonad[Cofree[F, ?]] |
176 |
| - def bind[F[_]: Plus: Functor] = Bind[Cofree[F, ?]] |
177 |
| - def monad[F[_]: PlusEmpty: Functor] = Monad[Cofree[F, ?]] |
178 |
| - def foldable1[F[_]: Foldable] = Foldable1[Cofree[F, ?]] |
179 |
| - def traverse1[F[_]: Traverse] = Traverse1[Cofree[F, ?]] |
180 |
| - |
181 |
| - // checking absence of ambiguity |
182 |
| - def bind[F[_]: PlusEmpty: Functor] = Bind[Cofree[F, ?]] |
183 |
| - def bind[F[_]: PlusEmpty: Traverse] = Bind[Cofree[F, ?]] |
184 |
| - def functor[F[_]: Traverse] = Functor[Cofree[F, ?]] |
185 |
| - def functor[F[_]: Traverse1] = Functor[Cofree[F, ?]] |
186 |
| - def functor[F[_]: Plus: Functor] = Functor[Cofree[F, ?]] |
187 |
| - def functor[F[_]: PlusEmpty: Traverse] = Functor[Cofree[F, ?]] |
188 |
| - def functor[F[_]: PlusEmpty: Traverse1] = Functor[Cofree[F, ?]] |
189 |
| - def foldable1[F[_]: Traverse1] = Foldable1[Cofree[F, ?]] |
190 |
| - def traverse1[F[_]: Traverse1] = Traverse1[Cofree[F, ?]] |
191 |
| - |
192 |
| - object zip{ |
193 |
| - def functor[F[_]: Functor] = Functor[CofreeZip[F, ?]] |
194 |
| - def apply[F[_]: Apply] = Apply[CofreeZip[F, ?]] |
195 |
| - def applicative[F[_]: Applicative] = Applicative[CofreeZip[F, ?]] |
196 |
| - |
197 |
| - // checking absence of ambiguity |
198 |
| - def functor[F[_]: Applicative] = Functor[CofreeZip[F, ?]] |
199 |
| - def apply[F[_]: Applicative] = Apply[CofreeZip[F, ?]] |
200 |
| - } |
201 |
| - |
202 |
| - } |
203 | 11 | }
|
0 commit comments