Skip to content

Commit

Permalink
Merge pull request #4414 from morgen-peschke/additional-defer-instances
Browse files Browse the repository at this point in the history
Add `Defer` instances for `Eq`, `Hash`, `Order`, `Show`, and variants
  • Loading branch information
johnynek authored Jul 10, 2023
2 parents 29b1546 + 71b6252 commit 65a3c5b
Show file tree
Hide file tree
Showing 22 changed files with 289 additions and 12 deletions.
1 change: 1 addition & 0 deletions core/src/main/scala-2.12/cats/instances/all.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ trait AllInstances
with PartialOrderingInstances
with QueueInstances
with SetInstances
with ShowInstances
with SortedMapInstances
with SortedSetInstances
with StreamInstances
Expand Down
1 change: 1 addition & 0 deletions core/src/main/scala-2.12/cats/instances/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ package object instances {
object set extends SetInstances
object seq extends SeqInstances
object short extends ShortInstances
object show extends ShowInstances
object sortedMap
extends SortedMapInstances
with SortedMapInstancesBinCompat0
Expand Down
1 change: 1 addition & 0 deletions core/src/main/scala-2.13+/cats/instances/all.scala
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ trait AllInstances
with SetInstances
with SortedMapInstances
with SortedSetInstances
with ShowInstances
with StreamInstances
with StringInstances
with SymbolInstances
Expand Down
1 change: 1 addition & 0 deletions core/src/main/scala-2.13+/cats/instances/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ package object instances {
object set extends SetInstances
object seq extends SeqInstances
object short extends ShortInstances
object show extends ShowInstances
object sortedMap
extends SortedMapInstances
with SortedMapInstancesBinCompat0
Expand Down
9 changes: 9 additions & 0 deletions core/src/main/scala/cats/Defer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,16 @@ trait Defer[F[_]] extends Serializable {
object Defer {
def apply[F[_]](implicit defer: Defer[F]): Defer[F] = defer

implicit def catsDeferForEq: Defer[Eq] = cats.implicits.catsDeferForEq
implicit def catsDeferForEquiv: Defer[Equiv] = cats.implicits.catsDeferForEquiv
implicit def catsDeferForFunction0: Defer[Function0] = cats.instances.function.catsSddDeferForFunction0
implicit def catsDeferForFunction1[A]: Defer[Function1[A, *]] = cats.instances.function.catsStdDeferForFunction1[A]
implicit def catsDeferForHash: Defer[Hash] = cats.implicits.catsDeferForHash
implicit def catsDeferForOrder: Defer[Order] = cats.instances.order.catsDeferForOrder
implicit def catsStdDeferForOrdering: Defer[Ordering] = cats.instances.ordering.catsStdDeferForOrdering
implicit def catsDeferForPartialOrder: Defer[PartialOrder] = cats.instances.partialOrder.catsDeferForPartialOrder
implicit def catsStdDeferForPartialOrdering: Defer[PartialOrdering] =
cats.instances.partialOrdering.catsStdDeferForPartialOrdering
implicit def catsDeferForShow: Defer[Show] = cats.implicits.catsDeferForShow
implicit def catsDeferForTailRec: Defer[TailRec] = cats.instances.tailRec.catsInstancesForTailRec
}
27 changes: 27 additions & 0 deletions core/src/main/scala/cats/instances/eq.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
package cats
package instances

import scala.annotation.tailrec

trait EqInstances extends kernel.instances.EqInstances {
implicit val catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] =
new ContravariantMonoidal[Eq] {
Expand All @@ -43,4 +45,29 @@ trait EqInstances extends kernel.instances.EqInstances {
def product[A, B](fa: Eq[A], fb: Eq[B]): Eq[(A, B)] =
(left, right) => fa.eqv(left._1, right._1) && fb.eqv(left._2, right._2)
}

implicit def catsDeferForEq: Defer[Eq] = EqInstances.catsDeferForEqCache
}
object EqInstances {
private val catsDeferForEqCache: Defer[Eq] =
new Defer[Eq] {
case class Deferred[A](fa: () => Eq[A]) extends Eq[A] {
private lazy val resolved: Eq[A] = {
@tailrec
def loop(f: () => Eq[A]): Eq[A] =
f() match {
case Deferred(f) => loop(f)
case next => next
}

loop(fa)
}
override def eqv(x: A, y: A): Boolean = resolved.eqv(x, y)
}

override def defer[A](fa: => Eq[A]): Eq[A] = {
lazy val cachedFa = fa
Deferred(() => cachedFa)
}
}
}
27 changes: 27 additions & 0 deletions core/src/main/scala/cats/instances/equiv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
package cats
package instances

import scala.annotation.tailrec

trait EquivInstances {
implicit val catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] =
new ContravariantMonoidal[Equiv] {
Expand Down Expand Up @@ -52,4 +54,29 @@ trait EquivInstances {
fa.equiv(l._1, r._1) && fb.equiv(l._2, r._2)
}
}

implicit def catsDeferForEquiv: Defer[Equiv] = EquivInstances.catsDeferForEquivCache
}
object EquivInstances {
private val catsDeferForEquivCache: Defer[Equiv] =
new Defer[Equiv] {
case class Deferred[A](fa: () => Equiv[A]) extends Equiv[A] {
private lazy val resolved: Equiv[A] = {
@tailrec
def loop(f: () => Equiv[A]): Equiv[A] =
f() match {
case Deferred(f) => loop(f)
case next => next
}

loop(fa)
}
override def equiv(x: A, y: A): Boolean = resolved.equiv(x, y)
}

override def defer[A](fa: => Equiv[A]): Equiv[A] = {
lazy val cachedFa = fa
Deferred(() => cachedFa)
}
}
}
16 changes: 10 additions & 6 deletions core/src/main/scala/cats/instances/function.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,17 @@ private[instances] trait FunctionInstancesBinCompat0 {
implicit val catsSddDeferForFunction0: Defer[Function0] =
new Defer[Function0] {
case class Deferred[A](fa: () => Function0[A]) extends Function0[A] {
def apply() = {
private lazy val resolved: Function0[A] = {
@annotation.tailrec
def loop(f: () => Function0[A]): A =
def loop(f: () => Function0[A]): Function0[A] =
f() match {
case Deferred(f) => loop(f)
case next => next()
case next => next
}

loop(fa)
}
def apply(): A = resolved()
}
def defer[A](fa: => Function0[A]): Function0[A] = {
lazy val cachedFa = fa
Expand All @@ -65,15 +67,17 @@ private[instances] trait FunctionInstancesBinCompat0 {
implicit def catsStdDeferForFunction1[A]: Defer[A => *] =
new Defer[A => *] {
case class Deferred[B](fa: () => A => B) extends (A => B) {
def apply(a: A) = {
private lazy val resolved: A => B = {
@annotation.tailrec
def loop(f: () => A => B): B =
def loop(f: () => A => B): A => B =
f() match {
case Deferred(f) => loop(f)
case next => next(a)
case next => next
}

loop(fa)
}
def apply(a: A): B = resolved(a)
}
def defer[B](fa: => A => B): A => B = {
lazy val cachedFa = fa
Expand Down
32 changes: 32 additions & 0 deletions core/src/main/scala/cats/instances/hash.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
package cats
package instances

import scala.annotation.tailrec

trait HashInstances extends kernel.instances.HashInstances {

implicit val catsContravariantForHash: Contravariant[Hash] =
Expand All @@ -34,4 +36,34 @@ trait HashInstances extends kernel.instances.HashInstances {

}

implicit def catsDeferForHash: Defer[Hash] = HashInstances.catsDeferForHashCache
}
object HashInstances {
private val catsDeferForHashCache: Defer[Hash] =
new Defer[Hash] {
case class Deferred[A](fa: () => Hash[A]) extends Hash[A] {
private lazy val resolve: Hash[A] = {
@tailrec
def loop(f: () => Hash[A]): Hash[A] =
f() match {
case Deferred(f) => loop(f)
case next => next
}

loop(fa)
}

override def hash(x: A): Int = resolve.hash(x)

/**
* Returns `true` if `x` and `y` are equivalent, `false` otherwise.
*/
override def eqv(x: A, y: A): Boolean = resolve.eqv(x, y)
}

override def defer[A](fa: => Hash[A]): Hash[A] = {
lazy val cachedFa = fa
Deferred(() => cachedFa)
}
}
}
27 changes: 27 additions & 0 deletions core/src/main/scala/cats/instances/order.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ package instances

import cats.kernel.instances.unit._

import scala.annotation.tailrec

trait OrderInstances extends kernel.instances.OrderInstances {

implicit val catsContravariantMonoidalForOrder: ContravariantMonoidal[Order] =
Expand All @@ -47,4 +49,29 @@ trait OrderInstances extends kernel.instances.OrderInstances {
if (z == 0) fb.compare(x._2, y._2) else z
}
}

implicit def catsDeferForOrder: Defer[Order] = OrderInstances.catsDeferForOrderCache
}
object OrderInstances {
private val catsDeferForOrderCache: Defer[Order] =
new Defer[Order] {
case class Deferred[A](fa: () => Order[A]) extends Order[A] {
private lazy val resolved: Order[A] = {
@tailrec
def loop(f: () => Order[A]): Order[A] =
f() match {
case Deferred(f) => loop(f)
case next => next
}

loop(fa)
}
override def compare(x: A, y: A): Int = resolved.compare(x, y)
}

override def defer[A](fa: => Order[A]): Order[A] = {
lazy val cachedFa = fa
Deferred(() => cachedFa)
}
}
}
27 changes: 27 additions & 0 deletions core/src/main/scala/cats/instances/ordering.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ package instances

import cats.kernel.instances.unit._

import scala.annotation.tailrec

trait OrderingInstances {
implicit val catsContravariantMonoidalForOrdering: ContravariantMonoidal[Ordering] =
new ContravariantMonoidal[Ordering] {
Expand All @@ -43,4 +45,29 @@ trait OrderingInstances {
}
}
}

implicit def catsStdDeferForOrdering: Defer[Ordering] = OrderingInstances.catsStdDeferForOrderingCache
}
object OrderingInstances {
private val catsStdDeferForOrderingCache: Defer[Ordering] =
new Defer[Ordering] {
case class Deferred[A](fa: () => Ordering[A]) extends Ordering[A] {
private lazy val resolved: Ordering[A] = {
@tailrec
def loop(f: () => Ordering[A]): Ordering[A] =
f() match {
case Deferred(f) => loop(f)
case next => next
}

loop(fa)
}
override def compare(x: A, y: A): Int = resolved.compare(x, y)
}

override def defer[A](fa: => Ordering[A]): Ordering[A] = {
lazy val cachedFa = fa
Deferred(() => cachedFa)
}
}
}
27 changes: 27 additions & 0 deletions core/src/main/scala/cats/instances/partialOrder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ package cats
package instances
import cats.kernel.instances.unit._

import scala.annotation.tailrec

trait PartialOrderInstances extends kernel.instances.PartialOrderInstances {
implicit val catsContravariantMonoidalForPartialOrder: ContravariantMonoidal[PartialOrder] =
new ContravariantMonoidal[PartialOrder] {
Expand All @@ -41,4 +43,29 @@ trait PartialOrderInstances extends kernel.instances.PartialOrderInstances {

def unit: PartialOrder[Unit] = Order[Unit]
}

implicit def catsDeferForPartialOrder: Defer[PartialOrder] = PartialOrderInstances.catsDeferForPartialOrderCache
}
object PartialOrderInstances {
private val catsDeferForPartialOrderCache: Defer[PartialOrder] =
new Defer[PartialOrder] {
case class Deferred[A](fa: () => PartialOrder[A]) extends PartialOrder[A] {
private lazy val resolved: PartialOrder[A] = {
@tailrec
def loop(f: () => PartialOrder[A]): PartialOrder[A] =
f() match {
case Deferred(f) => loop(f)
case next => next
}

loop(fa)
}
override def partialCompare(x: A, y: A): Double = resolved.partialCompare(x, y)
}

override def defer[A](fa: => PartialOrder[A]): PartialOrder[A] = {
lazy val cachedFa = fa
Deferred(() => cachedFa)
}
}
}
31 changes: 31 additions & 0 deletions core/src/main/scala/cats/instances/partialOrdering.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
package cats
package instances

import scala.annotation.tailrec

trait PartialOrderingInstances {
implicit val catsContravariantMonoidalForPartialOrdering: ContravariantMonoidal[PartialOrdering] =
new ContravariantMonoidal[PartialOrdering] {
Expand Down Expand Up @@ -50,4 +52,33 @@ trait PartialOrderingInstances {

def unit: PartialOrdering[Unit] = cats.instances.unit.catsKernelStdOrderForUnit.toOrdering
}

implicit def catsStdDeferForPartialOrdering: Defer[PartialOrdering] =
PartialOrderingInstances.catsStdDeferForPartialOrderingCache
}
object PartialOrderingInstances {
private val catsStdDeferForPartialOrderingCache: Defer[PartialOrdering] =
new Defer[PartialOrdering] {
case class Deferred[A](fa: () => PartialOrdering[A]) extends PartialOrdering[A] {
private lazy val resolve: PartialOrdering[A] = {
@tailrec
def loop(f: () => PartialOrdering[A]): PartialOrdering[A] =
f() match {
case Deferred(f) => loop(f)
case next => next
}

loop(fa)
}

override def tryCompare(x: A, y: A): Option[Int] = resolve.tryCompare(x, y)

override def lteq(x: A, y: A): Boolean = resolve.lteq(x, y)
}

override def defer[A](fa: => PartialOrdering[A]): PartialOrdering[A] = {
lazy val cachedFa = fa
Deferred(() => cachedFa)
}
}
}
Loading

0 comments on commit 65a3c5b

Please sign in to comment.