Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LowerBounded and UpperBounded type classes #2910

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions core/src/main/scala-2.12-/cats/instances/stream.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ trait LazyListInstances extends StreamInstances with StreamInstancesBinCompat0 {
val catsStdInstancesForLazyList = catsStdInstancesForStream
}

// For cross compile with backward compatibility
trait LazyListInstancesBinCompat0

trait StreamInstances extends cats.kernel.instances.StreamInstances {

implicit val catsStdInstancesForStream
Expand Down Expand Up @@ -193,3 +196,5 @@ trait StreamInstancesBinCompat0 {

}
}

trait StreamInstancesBinCompat1 extends cats.kernel.instances.StreamInstancesBinCompat0
3 changes: 3 additions & 0 deletions core/src/main/scala-2.13+/cats/instances/lazyList.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import scala.annotation.tailrec

//For cross compile with backward compatibility
trait StreamInstancesBinCompat0
trait StreamInstancesBinCompat1

//For cross compile with backward compatibility
trait StreamInstances extends LazyListInstances {
Expand Down Expand Up @@ -204,3 +205,5 @@ trait LazyListInstances extends cats.kernel.instances.StreamInstances {

}
}

trait LazyListInstancesBinCompat0 extends cats.kernel.instances.StreamInstancesBinCompat0
1 change: 1 addition & 0 deletions core/src/main/scala/cats/implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ object implicits
with instances.AllInstancesBinCompat3
with instances.AllInstancesBinCompat4
with instances.AllInstancesBinCompat5
with instances.AllInstancesBinCompat6
11 changes: 11 additions & 0 deletions core/src/main/scala/cats/instances/all.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,14 @@ trait AllInstancesBinCompat3 extends AllCoreDurationInstances
trait AllInstancesBinCompat4 extends SortedMapInstancesBinCompat1 with MapInstancesBinCompat1

trait AllInstancesBinCompat5 extends SortedSetInstancesBinCompat0

trait AllInstancesBinCompat6
extends EitherInstancesBinCompat0
with ListInstancesBinCompat1
with OptionInstancesBinCompat1
with QueueInstancesBinCompat0
with SetInstancesBinCompat0
with StreamInstancesBinCompat1
with TupleInstancesBinCompat0
with VectorInstancesBinCompat1
with UUIDInstancesBinCompat0
2 changes: 2 additions & 0 deletions core/src/main/scala/cats/instances/either.scala
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,5 @@ trait EitherInstances extends cats.kernel.instances.EitherInstances {
}
}
}

trait EitherInstancesBinCompat0 extends cats.kernel.instances.EitherInstancesBinCompat0
2 changes: 2 additions & 0 deletions core/src/main/scala/cats/instances/list.scala
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,5 @@ trait ListInstancesBinCompat0 {
.value
}
}

trait ListInstancesBinCompat1 extends cats.kernel.instances.ListInstancesBinCompat0
2 changes: 2 additions & 0 deletions core/src/main/scala/cats/instances/option.scala
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,5 @@ trait OptionInstancesBinCompat0 {

}
}

trait OptionInstancesBinCompat1 extends cats.kernel.instances.OptionInstancesBinCompat0
21 changes: 11 additions & 10 deletions core/src/main/scala/cats/instances/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package object instances {
with AllInstancesBinCompat3
with AllInstancesBinCompat4
with AllInstancesBinCompat5
with AllInstancesBinCompat6
object bigInt extends BigIntInstances
object bigDecimal extends BigDecimalInstances
object bitSet extends BitSetInstances
Expand All @@ -17,7 +18,7 @@ package object instances {
object char extends CharInstances
object double extends DoubleInstances
object duration extends CoreDurationInstances with DurationInstances
object either extends EitherInstances
object either extends EitherInstances with EitherInstancesBinCompat0
object eq extends EqInstances
object equiv extends EquivInstances
object float extends FloatInstances
Expand All @@ -26,26 +27,26 @@ package object instances {
object future extends FutureInstances
object int extends IntInstances
object invariant extends InvariantMonoidalInstances
object list extends ListInstances with ListInstancesBinCompat0
object list extends ListInstances with ListInstancesBinCompat0 with ListInstancesBinCompat1
object long extends LongInstances
object option extends OptionInstances with OptionInstancesBinCompat0
object option extends OptionInstances with OptionInstancesBinCompat0 with OptionInstancesBinCompat1
object map extends MapInstances with MapInstancesBinCompat0 with MapInstancesBinCompat1
object order extends OrderInstances
object ordering extends OrderingInstances
object parallel extends ParallelInstances
object partialOrder extends PartialOrderInstances
object partialOrdering extends PartialOrderingInstances
object queue extends QueueInstances
object set extends SetInstances
object queue extends QueueInstances with QueueInstancesBinCompat0
object set extends SetInstances with SetInstancesBinCompat0
object short extends ShortInstances
object sortedMap extends SortedMapInstances with SortedMapInstancesBinCompat0 with SortedMapInstancesBinCompat1
object sortedSet extends SortedSetInstances with SortedSetInstancesBinCompat0
object stream extends StreamInstances with StreamInstancesBinCompat0
object lazyList extends LazyListInstances
object stream extends StreamInstances with StreamInstancesBinCompat0 with StreamInstancesBinCompat1
object lazyList extends LazyListInstances with LazyListInstancesBinCompat0
object string extends StringInstances
object try_ extends TryInstances
object tuple extends TupleInstances with Tuple2InstancesBinCompat0
object tuple extends TupleInstances with Tuple2InstancesBinCompat0 with TupleInstancesBinCompat0
object unit extends UnitInstances
object uuid extends UUIDInstances
object vector extends VectorInstances with VectorInstancesBinCompat0
object uuid extends UUIDInstances with UUIDInstancesBinCompat0
object vector extends VectorInstances with VectorInstancesBinCompat0 with VectorInstancesBinCompat1
}
2 changes: 2 additions & 0 deletions core/src/main/scala/cats/instances/queue.scala
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,5 @@ trait QueueInstances extends cats.kernel.instances.QueueInstances {
fa.iterator.map(_.show).mkString("Queue(", ", ", ")")
}
}

trait QueueInstancesBinCompat0 extends cats.kernel.instances.QueueInstancesBinCompat0
2 changes: 2 additions & 0 deletions core/src/main/scala/cats/instances/set.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,5 @@ trait SetInstances extends cats.kernel.instances.SetInstances {
fa.toIterator.map(_.show).mkString("Set(", ", ", ")")
}
}

trait SetInstancesBinCompat0 extends cats.kernel.instances.SetInstancesBinCompat0
2 changes: 2 additions & 0 deletions core/src/main/scala/cats/instances/tuple.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import scala.annotation.tailrec

trait TupleInstances extends Tuple2Instances with cats.kernel.instances.TupleInstances

trait TupleInstancesBinCompat0 extends cats.kernel.instances.TupleInstancesBinCompat0

trait Tuple2InstancesBinCompat0 {

/**
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/scala/cats/instances/uuid.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ trait UUIDInstances extends cats.kernel.instances.UUIDInstances {
implicit val catsStdShowForUUID: Show[UUID] =
Show.fromToString[UUID]
}

trait UUIDInstancesBinCompat0 extends cats.kernel.instances.UUIDInstancesBinCompat0
2 changes: 2 additions & 0 deletions core/src/main/scala/cats/instances/vector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,5 @@ trait VectorInstancesBinCompat0 {
.value
}
}

trait VectorInstancesBinCompat1 extends cats.kernel.instances.VectorInstancesBinCompat0
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package cats.kernel.laws

import cats.kernel.{LowerBounded, PartialOrder, UpperBounded}

trait LowerBoundedLaws[A] extends PartialOrderLaws[A] {
implicit def B: LowerBounded[A]

def boundLteqv(x: A): IsEq[Boolean] =
E.lteqv(B.minBound, x) <-> true
}

object LowerBoundedLaws {
def apply[A](implicit ev: LowerBounded[A]): LowerBoundedLaws[A] =
new LowerBoundedLaws[A] {
def B: LowerBounded[A] = ev
def E: PartialOrder[A] = ev.partialOrder
}
}

trait UpperBoundedLaws[A] extends PartialOrderLaws[A] {
implicit def B: UpperBounded[A]

def boundGteqv(x: A): IsEq[Boolean] =
E.gteqv(B.maxBound, x) <-> true
}

object UpperBoundedLaws {
def apply[A](implicit ev: UpperBounded[A]): UpperBoundedLaws[A] =
new UpperBoundedLaws[A] {
def B: UpperBounded[A] = ev
def E: PartialOrder[A] = ev.partialOrder
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package cats
package kernel
package laws
package discipline

import cats.kernel.instances.boolean._
import org.scalacheck.Arbitrary
import org.scalacheck.Prop.forAll

trait LowerBoundedTests[A] extends PartialOrderTests[A] {
def laws: LowerBoundedLaws[A]

def lowerBounded(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqOA: Eq[Option[A]], eqA: Eq[A]): RuleSet =
new DefaultRuleSet(
"lowerBounded",
Some(partialOrder),
"bound is less than or equals" -> forAll(laws.boundLteqv _)
)
}

object LowerBoundedTests {
def apply[A: LowerBounded]: LowerBoundedTests[A] =
new LowerBoundedTests[A] { def laws: LowerBoundedLaws[A] = LowerBoundedLaws[A] }
}

trait UpperBoundedTests[A] extends PartialOrderTests[A] {
def laws: UpperBoundedLaws[A]

def upperBounded(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqOA: Eq[Option[A]], eqA: Eq[A]): RuleSet =
new DefaultRuleSet(
"upperBounded",
Some(partialOrder),
"bound is greater than or equals" -> forAll(laws.boundGteqv _)
)
}

object UpperBoundedTests {
def apply[A: UpperBounded]: UpperBoundedTests[A] =
new UpperBoundedTests[A] { def laws: UpperBoundedLaws[A] = UpperBoundedLaws[A] }
}
33 changes: 33 additions & 0 deletions kernel-laws/shared/src/test/scala/cats/kernel/laws/LawTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,39 @@ class Tests extends AnyFunSuiteLike with Discipline {
checkAll("Order.reverse(Order.reverse(Order[Int]))", OrderTests(Order.reverse(Order.reverse(Order[Int]))).order)
checkAll("Order.fromLessThan[Int](_ < _)", OrderTests(Order.fromLessThan[Int](_ < _)).order)

checkAll("LowerBounded[Unit]", LowerBoundedTests[Unit].lowerBounded)
checkAll("LowerBounded[Boolean]", LowerBoundedTests[Boolean].lowerBounded)
checkAll("LowerBounded[Byte]", LowerBoundedTests[Byte].lowerBounded)
checkAll("LowerBounded[Short]", LowerBoundedTests[Short].lowerBounded)
checkAll("LowerBounded[Char]", LowerBoundedTests[Char].lowerBounded)
checkAll("LowerBounded[Int]", LowerBoundedTests[Int].lowerBounded)
checkAll("LowerBounded[Long]", LowerBoundedTests[Long].lowerBounded)
checkAll("LowerBounded[Duration]", LowerBoundedTests[Duration].lowerBounded)
checkAll("LowerBounded[FiniteDuration]", LowerBoundedTests[FiniteDuration].lowerBounded)
checkAll("LowerBounded[UUID]", LowerBoundedTests[UUID].lowerBounded)
checkAll("LowerBounded[String]", LowerBoundedTests[String].lowerBounded)
checkAll("LowerBounded[Symbol]", LowerBoundedTests[Symbol].lowerBounded)
checkAll("LowerBounded[Option[Int]]", LowerBoundedTests[Option[Int]].lowerBounded)
checkAll("LowerBounded[Either[Int, String]]", LowerBoundedTests[Either[Int, String]].lowerBounded)
checkAll("LowerBounded[List[Int]]", LowerBoundedTests[List[Int]].lowerBounded)
checkAll("LowerBounded[Queue[Int]]", LowerBoundedTests[Queue[Int]].lowerBounded)
checkAll("LowerBounded[Set[Int]]", LowerBoundedTests[Set[Int]].lowerBounded)
checkAll("LowerBounded[Stream[Int]]", LowerBoundedTests[LazyList[Int]].lowerBounded)
checkAll("LowerBounded[Vector[Int]]", LowerBoundedTests[Vector[Int]].lowerBounded)

checkAll("UpperBounded[Unit]", UpperBoundedTests[Unit].upperBounded)
checkAll("UpperBounded[Boolean]", UpperBoundedTests[Boolean].upperBounded)
checkAll("UpperBounded[Byte]", UpperBoundedTests[Byte].upperBounded)
checkAll("UpperBounded[Short]", UpperBoundedTests[Short].upperBounded)
checkAll("UpperBounded[Char]", UpperBoundedTests[Char].upperBounded)
checkAll("UpperBounded[Int]", UpperBoundedTests[Int].upperBounded)
checkAll("UpperBounded[Long]", UpperBoundedTests[Long].upperBounded)
checkAll("UpperBounded[Duration]", UpperBoundedTests[Duration].upperBounded)
checkAll("UpperBounded[FiniteDuration]", UpperBoundedTests[FiniteDuration].upperBounded)
checkAll("UpperBounded[UUID]", UpperBoundedTests[UUID].upperBounded)
checkAll("UpperBounded[Option[Int]]", UpperBoundedTests[Option[Int]].upperBounded)
checkAll("UpperBounded[Either[String, Int]]", UpperBoundedTests[Either[String, Int]].upperBounded)

checkAll("Monoid[String]", MonoidTests[String].monoid)
checkAll("Monoid[String]", SerializableTests.serializable(Monoid[String]))
checkAll("Monoid[Option[Int]]", MonoidTests[Option[Int]].monoid)
Expand Down
43 changes: 43 additions & 0 deletions kernel/src/main/scala/cats/kernel/Bounded.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package cats.kernel

import scala.{specialized => sp}

/**
* A type class used to name the lower limit of a type.
*/
trait LowerBounded[@sp A] {
def partialOrder: PartialOrder[A]

/**
* Returns the lower limit of a type.
*/
def minBound: A
}

trait LowerBoundedFunctions[L[T] <: LowerBounded[T]] {
def minBound[@sp A](implicit ev: L[A]): A = ev.minBound
}

object LowerBounded extends LowerBoundedFunctions[LowerBounded] {
@inline def apply[A](implicit l: LowerBounded[A]): LowerBounded[A] = l
}

/**
* A type class used to name the upper limit of a type.
*/
trait UpperBounded[@sp A] {
def partialOrder: PartialOrder[A]

/**
* Returns the upper limit of a type.
*/
def maxBound: A
}

trait UpperBoundedFunctions[U[T] <: UpperBounded[T]] {
def maxBound[@sp A](implicit ev: U[A]): A = ev.maxBound
}

object UpperBounded extends UpperBoundedFunctions[UpperBounded] {
@inline def apply[A](implicit u: UpperBounded[A]): UpperBounded[A] = u
}
11 changes: 11 additions & 0 deletions kernel/src/main/scala/cats/kernel/instances/AllInstances.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,14 @@ trait AllInstances
with VectorInstances

trait AllInstancesBinCompat0 extends FiniteDurationInstances

trait AllInstancesBinCompat1
extends EitherInstancesBinCompat0
with ListInstancesBinCompat0
with OptionInstancesBinCompat0
with QueueInstancesBinCompat0
with SetInstancesBinCompat0
with StreamInstancesBinCompat0
with TupleInstancesBinCompat0
with UUIDInstancesBinCompat0
with VectorInstancesBinCompat0
13 changes: 10 additions & 3 deletions kernel/src/main/scala/cats/kernel/instances/BooleanInstances.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ package cats.kernel
package instances

trait BooleanInstances {
implicit val catsKernelStdOrderForBoolean: Order[Boolean] with Hash[Boolean] =
new BooleanOrder
implicit val catsKernelStdOrderForBoolean
: Order[Boolean] with Hash[Boolean] with LowerBounded[Boolean] with UpperBounded[Boolean] = new BooleanOrder
}

class BooleanOrder extends Order[Boolean] with Hash[Boolean] {
trait BooleanBounded extends LowerBounded[Boolean] with UpperBounded[Boolean] {
override def minBound: Boolean = false
override def maxBound: Boolean = true
}

class BooleanOrder extends Order[Boolean] with Hash[Boolean] with BooleanBounded { self =>

def hash(x: Boolean): Int = x.hashCode()
def compare(x: Boolean, y: Boolean): Int =
Expand All @@ -21,4 +26,6 @@ class BooleanOrder extends Order[Boolean] with Hash[Boolean] {

override def min(x: Boolean, y: Boolean): Boolean = x && y
override def max(x: Boolean, y: Boolean): Boolean = x || y

override val partialOrder: PartialOrder[Boolean] = self
}
12 changes: 10 additions & 2 deletions kernel/src/main/scala/cats/kernel/instances/ByteInstances.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,24 @@ package cats.kernel
package instances

trait ByteInstances {
implicit val catsKernelStdOrderForByte: Order[Byte] with Hash[Byte] = new ByteOrder
implicit val catsKernelStdOrderForByte: Order[Byte] with Hash[Byte] with LowerBounded[Byte] with UpperBounded[Byte] =
new ByteOrder
implicit val catsKernelStdGroupForByte: CommutativeGroup[Byte] = new ByteGroup
}

trait ByteBounded extends LowerBounded[Byte] with UpperBounded[Byte] {
override def minBound: Byte = Byte.MinValue
override def maxBound: Byte = Byte.MaxValue
}

class ByteGroup extends CommutativeGroup[Byte] {
def combine(x: Byte, y: Byte): Byte = (x + y).toByte
def empty: Byte = 0
def inverse(x: Byte): Byte = (-x).toByte
override def remove(x: Byte, y: Byte): Byte = (x - y).toByte
}

class ByteOrder extends Order[Byte] with Hash[Byte] {
class ByteOrder extends Order[Byte] with Hash[Byte] with ByteBounded { self =>

def hash(x: Byte): Int = x.hashCode()

Expand All @@ -31,4 +37,6 @@ class ByteOrder extends Order[Byte] with Hash[Byte] {
java.lang.Math.min(x.toInt, y.toInt).toByte
override def max(x: Byte, y: Byte): Byte =
java.lang.Math.max(x.toInt, y.toInt).toByte

override val partialOrder: PartialOrder[Byte] = self
}
Loading