Skip to content

Commit

Permalink
feat: Add semigroup for numerical types
Browse files Browse the repository at this point in the history
  • Loading branch information
Iltotore committed Oct 10, 2024
1 parent 0f02adb commit ebfa7ca
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 37 deletions.
56 changes: 29 additions & 27 deletions cats/src/io/github/iltotore/iron/instances.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package io.github.iltotore.iron

import _root_.cats.kernel.{CommutativeMonoid, Hash, LowerBounded, PartialOrder, UpperBounded}
import _root_.cats.kernel.{CommutativeSemigroup, Hash, LowerBounded, PartialOrder, UpperBounded}
import _root_.cats.{Eq, Monoid, Order, Show, Traverse}
import io.github.iltotore.iron.constraint.numeric.*
import scala.util.NotGiven
import _root_.cats.Functor
import algebra.instances.all.*
import algebra.ring.AdditiveCommutativeSemigroup

/**
* Represent all Cats' typeclass instances for Iron.
Expand All @@ -30,35 +32,20 @@ private[iron] trait IronCatsInstances extends IronCatsLowPriority, RefinedTypeOp
inline given [A, C, V](using inline ev: UpperBounded[A], implication: C ==> Greater[V]): UpperBounded[A :| C] =
ev.asInstanceOf[UpperBounded[A :| C]]

private def posMonoid[A, C](using ev: CommutativeMonoid[A], shift: PosShift[A], implication: C ==> Positive): CommutativeMonoid[A :| C] =
new CommutativeMonoid[A :| C]:
private def commutativeSemigroup[A, C](using inner: CommutativeSemigroup[A], bounds: Bounds[A, C]): CommutativeSemigroup[A :| C] =
new CommutativeSemigroup[A :| C]:

override def empty: A :| C = ev.empty.asInstanceOf[A :| C]
override def combine(a: A :| C, b: A :| C): A :| C = bounds.shift(inner.combine(a, b))

override def combine(a: A :| C, b: A :| C): A :| C = shift.shift(ev.combine(a, b)).asInstanceOf[A :| C]
given posIntCommutativeSemigroup: CommutativeSemigroup[Int :| Positive] = commutativeSemigroup[Int, Positive]
given posLongCommutativeSemigroup: CommutativeSemigroup[Long :| Positive] = commutativeSemigroup[Long, Positive]
given posFloatCommutativeSemigroup: CommutativeSemigroup[Float :| Positive] = commutativeSemigroup[Float, Positive]
given posDoubleCommutativeSemigroup: CommutativeSemigroup[Double :| Positive] = commutativeSemigroup[Double, Positive]

inline given posIntCommutativeMonoid[C](using C ==> Positive): CommutativeMonoid[Int :| C] = posMonoid

inline given posLongCommutativeMonoid[C](using C ==> Positive): CommutativeMonoid[Long :| C] = posMonoid

inline given posFloatCommutativeMonoid[C](using C ==> Positive): CommutativeMonoid[Float :| C] = posMonoid

inline given posDoubleCommutativeMonoid[C](using C ==> Positive): CommutativeMonoid[Double :| C] = posMonoid

private def negMonoid[A, C](using ev: CommutativeMonoid[A], shift: NegShift[A], implication: C ==> Negative): CommutativeMonoid[A :| C] =
new CommutativeMonoid[A :| C]:

override def empty: A :| C = ev.empty.asInstanceOf[A :| C]

override def combine(a: A :| C, b: A :| C): A :| C = shift.shift(ev.combine(a, b)).asInstanceOf[A :| C]

inline given negIntCommutativeMonoid[C](using C ==> Negative): CommutativeMonoid[Int :| C] = negMonoid

inline given negLongCommutativeMonoid[C](using C ==> Negative): CommutativeMonoid[Long :| C] = negMonoid

inline given negFloatCommutativeMonoid[C](using C ==> Negative): CommutativeMonoid[Float :| C] = negMonoid

inline given negDoubleCommutativeMonoid[C](using C ==> Negative): CommutativeMonoid[Double :| C] = negMonoid
given negIntCommutativeSemigroup: CommutativeSemigroup[Int :| Negative] = commutativeSemigroup[Int, Negative]
given negLongCommutativeSemigroup: CommutativeSemigroup[Long :| Negative] = commutativeSemigroup[Long, Negative]
given negFloatCommutativeSemigroup: CommutativeSemigroup[Float :| Negative] = commutativeSemigroup[Float, Negative]
given negDoubleCommutativeSemigroup: CommutativeSemigroup[Double :| Negative] = commutativeSemigroup[Double, Negative]

/**
* Cats' instances for Iron that need to have a lower priority to avoid ambiguous implicits.
Expand All @@ -80,3 +67,18 @@ private trait RefinedTypeOpsCats extends RefinedTypeOpsCatsLowPriority:
private trait RefinedTypeOpsCatsLowPriority:

inline given [T](using mirror: RefinedTypeOps.Mirror[T], ev: Hash[mirror.IronType]): Hash[T] = ev.asInstanceOf[Hash[T]]

private def additiveCommutativeSemigroup[A, C](using inner: AdditiveCommutativeSemigroup[A], bounds: Bounds[A, C]): AdditiveCommutativeSemigroup[A :| C] = (x, y) =>
bounds.shift(inner.plus(x, y))

given posIntAdditiveCommutativeSemigroup: AdditiveCommutativeSemigroup[Int :| Positive] = additiveCommutativeSemigroup[Int, Positive]
given posLongAdditiveCommutativeSemigroup: AdditiveCommutativeSemigroup[Long :| Positive] = additiveCommutativeSemigroup[Long, Positive]
given posFloatAdditiveCommutativeSemigroup: AdditiveCommutativeSemigroup[Float :| Positive] = additiveCommutativeSemigroup[Float, Positive]
given posDoubleAdditiveCommutativeSemigroup: AdditiveCommutativeSemigroup[Double :| Positive] = additiveCommutativeSemigroup[Double, Positive]

given negIntAdditiveCommutativeSemigroup: AdditiveCommutativeSemigroup[Int :| Negative] = additiveCommutativeSemigroup[Int, Negative]
given negLongAdditiveCommutativeSemigroup: AdditiveCommutativeSemigroup[Long :| Negative] = additiveCommutativeSemigroup[Long, Negative]
given negFloatAdditiveCommutativeSemigroup: AdditiveCommutativeSemigroup[Float :| Negative] = additiveCommutativeSemigroup[Float, Negative]
given negDoubleAdditiveCommutativeSemigroup: AdditiveCommutativeSemigroup[Double :| Negative] = additiveCommutativeSemigroup[Double, Negative]


37 changes: 27 additions & 10 deletions cats/test/src/io/github/iltotore/iron/CatsSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import _root_.cats.data.NonEmptyList
import _root_.cats.data.Validated.{Invalid, Valid}

import scala.runtime.stdLibPatches.Predef.assert
import algebra.ring.AdditiveCommutativeSemigroup

object CatsSuite extends TestSuite:

Expand Down Expand Up @@ -68,23 +69,39 @@ object CatsSuite extends TestSuite:
Show[Person]

test("alley") {
test("commutativeMonoid") {
test("commutativeSemigroup"):
test("int"):
test("pos") - assert(CommutativeMonoid[Int :| Positive].combine(1, 5) == 6)
test("neg") - assert(CommutativeMonoid[Int :| Negative].combine(-1, -5) == -6)
test("pos") - assert(CommutativeSemigroup[Int :| Positive].combine(1, 5) == 6)
test("neg") - assert(CommutativeSemigroup[Int :| Negative].combine(-1, -5) == -6)

test("long"):
test("pos") - assert(CommutativeMonoid[Long :| Positive].combine(1, 5) == 6)
test("neg") - assert(CommutativeMonoid[Long :| Negative].combine(-1, -5) == -6)
test("pos") - assert(CommutativeSemigroup[Long :| Positive].combine(1, 5) == 6)
test("neg") - assert(CommutativeSemigroup[Long :| Negative].combine(-1, -5) == -6)

test("float"):
test("pos") - assert(CommutativeMonoid[Float :| Positive].combine(1, 5) == 6)
test("neg") - assert(CommutativeMonoid[Float :| Negative].combine(-1, -5) == -6)
test("pos") - assert(CommutativeSemigroup[Float :| Positive].combine(1, 5) == 6)
test("neg") - assert(CommutativeSemigroup[Float :| Negative].combine(-1, -5) == -6)

test("double"):
test("pos") - assert(CommutativeMonoid[Double :| Positive].combine(1, 5) == 6)
test("neg") - assert(CommutativeMonoid[Double :| Negative].combine(-1, -5) == -6)
}
test("pos") - assert(CommutativeSemigroup[Double :| Positive].combine(1, 5) == 6)
test("neg") - assert(CommutativeSemigroup[Double :| Negative].combine(-1, -5) == -6)

test("additiveCommutativeSemigroup"):
test("int"):
test("pos") - assert(AdditiveCommutativeSemigroup[Int :| Positive].plus(1, 5) == 6)
test("neg") - assert(AdditiveCommutativeSemigroup[Int :| Negative].plus(-1, -5) == -6)

test("long"):
test("pos") - assert(AdditiveCommutativeSemigroup[Long :| Positive].plus(1, 5) == 6)
test("neg") - assert(AdditiveCommutativeSemigroup[Long :| Negative].plus(-1, -5) == -6)

test("float"):
test("pos") - assert(AdditiveCommutativeSemigroup[Float :| Positive].plus(1, 5) == 6)
test("neg") - assert(AdditiveCommutativeSemigroup[Float :| Negative].plus(-1, -5) == -6)

test("double"):
test("pos") - assert(AdditiveCommutativeSemigroup[Double :| Positive].plus(1, 5) == 6)
test("neg") - assert(AdditiveCommutativeSemigroup[Double :| Negative].plus(-1, -5) == -6)
}

test("eitherNec"):
Expand Down

0 comments on commit ebfa7ca

Please sign in to comment.