|
Scala example source code file (CofreeTest.scala)
The CofreeTest.scala Scala example source code
package scalaz
import scalaz.scalacheck.ScalazProperties
import scalaz.scalacheck.ScalazProperties._
import scalaz.scalacheck.ScalazArbitrary._
import scalaz.scalacheck.ScalaCheckBinding._
import std.AllInstances._
import org.scalacheck.Arbitrary
import org.scalacheck.Prop.forAll
import Cofree._
import Cofree.CofreeZip
import Isomorphism._
object CofreeTest extends SpecLite {
type CofreeLazyOption[A] = Cofree[LazyOption, A]
type CofreeStream[A] = Cofree[Stream, A]
type OneAndStream[A] = OneAnd[Stream, A]
type OneAndList[A] = OneAnd[List, A]
type CofreeOption[A] = Cofree[Option, A]
implicit def cofreeEqual[F[_], A](implicit F: Eq1[F], A: Equal[A]): Equal[Cofree[F, A]] =
Equal.equal{ (a, b) =>
A.equal(a.head, b.head) && F.eq1(cofreeEqual[F, A]).equal(a.tail, b.tail)
}
implicit def cofreeZipEqual[F[_]: Eq1, A: Equal]: Equal[CofreeZip[F, A]] =
Tag.subst(cofreeEqual[F, A])
//needed to prevent SOE for testing with equality
implicit def cofreeOptEquals[A](implicit e: Equal[A]): Equal[CofreeOption[A]] = new Equal[CofreeOption[A]] {
override def equal(a: CofreeOption[A], b: CofreeOption[A]): Boolean = {
def tr(a: CofreeOption[A], b: CofreeOption[A]): Boolean =
(a.tail, b.tail) match {
case (Some(at), Some(bt)) if (e.equal(a.head, b.head)) => tr(at, bt)
case (None, None) if (e.equal(a.head, b.head)) => true
case _ => false
}
tr(a,b)
}
}
val oneAndListNat: OneAndList ~> CofreeOption =
new (OneAndList ~> CofreeOption) {
def apply[A](fa: OneAndList[A]): CofreeOption[A] =
Cofree.unfold(fa) {
case OneAnd(a, h :: t) =>
(a, Some(OneAnd(h, t)))
case OneAnd(a, _) => (a, None)
}
}
val oneAndStreamCofreeLazyOptionIso: OneAndStream <~> CofreeLazyOption =
new IsoFunctorTemplate[OneAndStream, CofreeLazyOption] {
def to[A](fa: OneAndStream[A]) =
Cofree.unfold(fa){
case OneAnd(a, h #:: t) => (a, LazyOption.lazySome(OneAnd(h, t)))
case OneAnd(a, _) => (a, LazyOption.lazyNone)
}
def from[A](fa: CofreeLazyOption[A]) =
OneAnd(
fa.head,
fa.tail.map(s =>
Foldable[CofreeLazyOption].foldRight(s, Stream.empty[A])(_ #:: _)
).getOrElse(Stream.empty)
)
}
val treeCofreeStreamIso: Tree <~> CofreeStream =
new IsoFunctorTemplate[Tree, CofreeStream] {
def to[A](tree: Tree[A]): CofreeStream[A] =
Cofree(tree.rootLabel, tree.subForest.map(to))
def from[A](c: CofreeStream[A]): Tree[A] =
Tree.Node(c.head, c.tail.map(from(_)))
}
implicit def CofreeLazyOptionArb[A: Arbitrary]: Arbitrary[CofreeLazyOption[A]] =
Functor[Arbitrary].map(implicitly[Arbitrary[OneAndStream[A]]])(oneAndStreamCofreeLazyOptionIso.to(_))
implicit def CofreeStreamArb[A: Arbitrary]: Arbitrary[CofreeStream[A]] =
Functor[Arbitrary].map(implicitly[Arbitrary[Tree[A]]])(treeCofreeStreamIso.to)
implicit def CofreeOptionArb[A: Arbitrary]: Arbitrary[CofreeOption[A]] = {
import org.scalacheck.Arbitrary._
import org.scalacheck.Gen
val arb = Arbitrary { Gen.listOfN(5000, implicitly[Arbitrary[A]].arbitrary ) }
Functor[Arbitrary].map(arb){
case h :: Nil => oneAndListNat( OneAnd(h, Nil))
case h :: t => oneAndListNat( OneAnd(h, t) )
}
}
checkAll("CofreeLazyOption", comonad.laws[CofreeLazyOption])
checkAll("CofreeLazyOption", traverse1.laws[CofreeLazyOption])
checkAll("CofreeLazyOption", monad.laws[CofreeLazyOption])
checkAll("CofreeLazyOption", equal.laws[CofreeLazyOption[Int]])
checkAll("CofreeStream", comonad.laws[CofreeStream])
checkAll("CofreeStream", traverse1.laws[CofreeStream])
checkAll("CofreeStream", monad.laws[CofreeStream])
checkAll("CofreeStream", equal.laws[CofreeStream[Int]])
checkAll("CofreeOption", comonad.laws[CofreeOption])
checkAll("CofreeOption", monad.laws[CofreeOption])
{
type CofreeZipLazyOption[A] = CofreeZip[LazyOption, A]
implicit def CofreeZipLazyOptionArb[A: Arbitrary]: Arbitrary[CofreeZipLazyOption[A]] =
Tags.Zip.subst(CofreeLazyOptionArb[A])
// Hack: avoid stack overflow because `Applicative[CofreeLazyOption].point` is infinite stream
def CofreeZipLazyOptionEqual[A: Equal]: Equal[CofreeZipLazyOption[A]] =
Equal.equalBy{ a =>
val OneAnd(h, t) = oneAndStreamCofreeLazyOptionIso.from(Tag.unwrap(a))
h -> t.take(1000)
}
checkAll("CofreeZipLazyOption", applicative.laws[CofreeZipLazyOption](implicitly, implicitly, implicitly, CofreeZipLazyOptionEqual))
}
{
type CofreeZipStream[A] = CofreeZip[Stream, A]
implicit def CofreeZipStreamArb[A: Arbitrary]: Arbitrary[CofreeZipStream[A]] =
Tags.Zip.subst(CofreeStreamArb[A])
checkAll("CofreeZipStream", ScalazProperties.apply.laws[CofreeZipStream])
}
"no stack overflow Applicative[CofreeZip[IList, ?]]#point" in {
val a = 1
val b = Applicative[CofreeZip[IList, ?]].point(a)
val size = 10
Foldable[Cofree[IList, ?]].toStream(Tag.unwrap(b)).take(size) must_=== Stream.fill(size)(a)
}
"Applicative[λ[α => CofreeZip[LazyOption, α]]] is Applicative[λ[α => Stream[α] @@ Zip]]" ! forAll{
(a: OneAndStream[Int], b: OneAndStream[Int]) =>
import syntax.foldable._
val f = (_: Int) + (_: Int)
val h #:: t = Tag.unwrap(Applicative[λ[α => Stream[α] @@ Tags.Zip]].apply2(Tags.Zip[Stream[Int]](a.toStream), Tags.Zip[Stream[Int]](b.toStream))(f))
val aa = Tags.Zip(oneAndStreamCofreeLazyOptionIso.to(a))
val bb = Tags.Zip(oneAndStreamCofreeLazyOptionIso.to(b))
val y = Applicative[λ[α => CofreeZip[LazyOption, α]]].apply2(aa, bb)(f)
OneAnd(h, t) must_=== oneAndStreamCofreeLazyOptionIso.from(Tag.unwrap(y))
}
"no stack overflow unfoldC, mapBranching" in {
import syntax.foldable._
val n = 100
val list = Cofree.unfoldC(1)(a => Option(a + 1)).mapBranching(NaturalTransformation.refl).toStream.take(n).toList
list must_=== (1 to n).toList
}
object instances{
def comonad[F[_]: Functor] = Comonad[Cofree[F, ?]]
def bind[F[_]: Plus: Functor] = Bind[Cofree[F, ?]]
def monad[F[_]: PlusEmpty: Functor] = Monad[Cofree[F, ?]]
def foldable1[F[_]: Foldable] = Foldable1[Cofree[F, ?]]
def traverse1[F[_]: Traverse] = Traverse1[Cofree[F, ?]]
// checking absence of ambiguity
def bind[F[_]: PlusEmpty: Functor] = Bind[Cofree[F, ?]]
def functor[F[_]: PlusEmpty: Traverse] = Functor[Cofree[F, ?]]
def foldable1[F[_]: Traverse1] = Foldable1[Cofree[F, ?]]
def traverse1[F[_]: Traverse1] = Traverse1[Cofree[F, ?]]
object zip{
def functor[F[_]: Functor] = Functor[CofreeZip[F, ?]]
def apply[F[_]: Apply] = Apply[CofreeZip[F, ?]]
def applicative[F[_]: Applicative] = Applicative[CofreeZip[F, ?]]
// checking absence of ambiguity
def functor[F[_]: Applicative] = Functor[CofreeZip[F, ?]]
def apply[F[_]: Applicative] = Apply[CofreeZip[F, ?]]
}
}
}
Other Scala examples (source code examples)Here is a short list of links related to this Scala CofreeTest.scala source code file: |
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.