From 4bb9936fd26992c236f617de6101639d72069167 Mon Sep 17 00:00:00 2001 From: Zach Albia Date: Tue, 11 May 2021 16:35:25 +0800 Subject: [PATCH] integrate subset of pr #449 --- .../scala/zio/prelude/AssociativeBoth.scala | 17 +++++++++++++- .../main/scala/zio/prelude/Covariant.scala | 17 ++++++++++++++ .../src/main/scala/zio/prelude/Derive.scala | 22 +++++++++++++++++++ .../src/main/scala/zio/prelude/Equal.scala | 12 ++++++++++ .../scala/zio/prelude/newtypes/package.scala | 10 +++++++++ 5 files changed, 77 insertions(+), 1 deletion(-) diff --git a/core/shared/src/main/scala/zio/prelude/AssociativeBoth.scala b/core/shared/src/main/scala/zio/prelude/AssociativeBoth.scala index e4fd60932..34b04b66c 100644 --- a/core/shared/src/main/scala/zio/prelude/AssociativeBoth.scala +++ b/core/shared/src/main/scala/zio/prelude/AssociativeBoth.scala @@ -18,7 +18,7 @@ package zio.prelude import zio._ import zio.prelude.coherent.AssociativeBothDeriveEqualInvariant -import zio.prelude.newtypes.{AndF, Failure, OrF} +import zio.prelude.newtypes.{AndF, Failure, Nested, OrF} import zio.stm.ZSTM import zio.stream.{ZSink, ZStream} import zio.test.TestResult @@ -1158,6 +1158,21 @@ object AssociativeBoth extends LawfulF.Invariant[AssociativeBothDeriveEqualInvar Id(Id.unwrap(fa) -> Id.unwrap(fb)) } + /** + * The `IdentityBoth` (and `AssociativeBoth`) instance for `Nested[F, G, A]`. + */ + implicit def NestedIdentityBoth[F[+_]: IdentityBoth: Covariant, G[+_]](implicit + G: IdentityBoth[G] + ): IdentityBoth[({ type lambda[+A] = Nested[F, G, A] })#lambda] = + new IdentityBoth[({ type lambda[+A] = Nested[F, G, A] })#lambda] { + override def any: Nested[F, G, Any] = Nested(G.any.succeed[F]) + + override def both[A, B](fa: => Nested[F, G, A], fb: => Nested[F, G, B]): Nested[F, G, (A, B)] = + Nested { + Nested.unwrap[F[G[A]]](fa).zipWith(Nested.unwrap[F[G[B]]](fb))(_ zip _) + } + } + /** * The `IdentityBoth` (and `AssociativeBoth`) instance for `List`. */ diff --git a/core/shared/src/main/scala/zio/prelude/Covariant.scala b/core/shared/src/main/scala/zio/prelude/Covariant.scala index 497e99616..899d333b6 100644 --- a/core/shared/src/main/scala/zio/prelude/Covariant.scala +++ b/core/shared/src/main/scala/zio/prelude/Covariant.scala @@ -17,6 +17,7 @@ package zio.prelude import zio.prelude.coherent.CovariantDeriveEqual +import zio.prelude.newtypes.Nested import zio.test.TestResult import zio.test.laws._ @@ -111,6 +112,22 @@ object Covariant extends LawfulF.Covariant[CovariantDeriveEqual, Equal] { def apply[F[+_]](implicit covariant: Covariant[F]): Covariant[F] = covariant + /** + * Constructs the instance for `Covariant[({ type lambda[+A] = Nested[F, G, A] })#lambda]` + * given a pair of pre-existing `Covariant` instances for covariant, higher-kinded type + * parameters `F[+_]` and `G[+_]`. + */ + implicit def NestedCovariant[F[+_], G[+_]](implicit + F: Covariant[F], + G: Covariant[G] + ): Covariant[({ type lambda[+A] = Nested[F, G, A] })#lambda] = + new Covariant[({ type lambda[+A] = Nested[F, G, A] })#lambda] { + private lazy val composedCovariant = F.compose(G) + + override def map[A, B](f: A => B): Nested[F, G, A] => Nested[F, G, B] = { x: Nested[F, G, A] => + Nested(composedCovariant.map(f)(Nested.unwrap[F[G[A]]](x))) + } + } } trait CovariantSyntax { diff --git a/core/shared/src/main/scala/zio/prelude/Derive.scala b/core/shared/src/main/scala/zio/prelude/Derive.scala index 8b8864dca..16057fe07 100644 --- a/core/shared/src/main/scala/zio/prelude/Derive.scala +++ b/core/shared/src/main/scala/zio/prelude/Derive.scala @@ -17,6 +17,7 @@ package zio.prelude import zio.{Cause, Chunk, Exit, NonEmptyChunk} +import zio.prelude.newtypes.Nested import scala.util.Try @@ -47,6 +48,27 @@ object Derive { def apply[F[_], Typeclass[_]](implicit derive: Derive[F, Typeclass]): Derive[F, Typeclass] = derive + + /** + * The `DeriveEqual` instance for `Id`. + */ + implicit val IdDeriveEqual: Derive[Id, Equal] = + new Derive[Id, Equal] { + override def derive[A: Equal]: Equal[Id[A]] = Id.wrapAll(Equal[A]) + } + + /** + * The `DeriveEqual` instance for `Nested`. + */ + implicit def NestedDeriveEqual[F[+_], G[+_]](implicit + F: Derive[F, Equal], + G: Derive[G, Equal] + ): Derive[({ type lambda[A] = Nested[F, G, A] })#lambda, Equal] = + new Derive[({ type lambda[A] = Nested[F, G, A] })#lambda, Equal] { + override def derive[A: Equal]: Equal[Nested[F, G, A]] = + Equal.NestedEqual(F.derive(G.derive[A])) + } + /** * The `DeriveEqual` instance for `Chunk`. */ diff --git a/core/shared/src/main/scala/zio/prelude/Equal.scala b/core/shared/src/main/scala/zio/prelude/Equal.scala index 28283bb0d..22ce8e22a 100644 --- a/core/shared/src/main/scala/zio/prelude/Equal.scala +++ b/core/shared/src/main/scala/zio/prelude/Equal.scala @@ -18,6 +18,7 @@ package zio.prelude import zio.Exit.{Failure, Success} import zio.prelude.coherent.{HashOrd, HashPartialOrd} +import zio.prelude.newtypes.Nested import zio.test.TestResult import zio.test.laws.{Lawful, Laws} import zio.{Cause, Chunk, Exit, Fiber, NonEmptyChunk, ZTrace} @@ -220,6 +221,17 @@ object Equal extends Lawful[Equal] { def default[A]: Equal[A] = DefaultEqual + implicit def IdEqual[A: Equal]: Equal[Id[A]] = new Equal[Id[A]] { + override protected def checkEqual(l: Id[A], r: Id[A]): Boolean = + Id.unwrap[A](l) === Id.unwrap[A](r) + } + + implicit def NestedEqual[F[+_], G[+_], A](implicit eqFGA: Equal[F[G[A]]]): Equal[Nested[F, G, A]] = + new Equal[Nested[F, G, A]] { + override protected def checkEqual(l: Nested[F, G, A], r: Nested[F, G, A]): Boolean = + eqFGA.checkEqual(Nested.unwrap[F[G[A]]](l), Nested.unwrap[F[G[A]]](r)) + } + /** * `Hash` and `Ord` (and thus also `Equal`) instance for `Boolean` values. */ diff --git a/core/shared/src/main/scala/zio/prelude/newtypes/package.scala b/core/shared/src/main/scala/zio/prelude/newtypes/package.scala index 8f573f59a..3bc19ca52 100644 --- a/core/shared/src/main/scala/zio/prelude/newtypes/package.scala +++ b/core/shared/src/main/scala/zio/prelude/newtypes/package.scala @@ -108,6 +108,16 @@ package object newtypes { type FailureOut[+A] = FailureOut.Type[A] + /** + * A newtype representing Right-to-left composition of functors. + * If F[_] and G[_] are both Covariant, then Nested[F, G, *] is also a Covariant + * If F[_] and G[_] are both IdentityBoth, then Nested[F, G, *] is also an IdentityBoth + * If F[_] and G[_] are both Traversable, then Nested[F, G, *] is also a Traversable + */ + object Nested extends NewtypeF + + type Nested[F[+_], G[+_], +A] = Nested.Type[F[G[A]]] + object Natural extends SubtypeSmart[Int](isGreaterThanEqualTo(0)) { val one: Natural =