import cats._
import cats.implicits._
object SemigroupInstances {
implicit val intSemigroup: Semigroup[Int] = new Semigroup[Int] {
override def combine(a: Int, b: Int) = a * b
}
}
import SemigroupInstances._
object Semigroup {
def apply[T](implicit instance: Semigroup[T]): Semigroup[T] = instance
}
val intSemigroup = Semigroup[Int]
intSemigroup.combine(4, 4) // expected 16, actual 8
So, how to make custom intSemigroup
working?
You import two instances of Semigroup[Int]
:
import cats.implicits._
import SemigroupInstances._
The compiler chooses the one from cats.implicits._
over your custom instance.
If you remove that import, it works: https://scastie.scala-lang.org/avsmEturTRGkNEOCDxuXOA
If you want to know more about how the compiler chooses which implicit instance to use, see this post: Where does Scala look for implicits?
In your specific case, the reason appears to be that the type of the instance from cats is actually CommutativeGroup[Int]
:
implicit val catsKernelStdGroupForInt: CommutativeGroup[Int] = new IntGroup
Hence, being a derived class (CommutativeGroup
extends Semigroup
), it is considered more specific and hence preferred.
If you change the type of your instance to CommutativeGroup[Int]
(which is not possible without being mathematically incorrect, but that's not the point here), you get an "Ambiguous given instances" error because the compiler cannot decide which instance to use: https://scastie.scala-lang.org/dzClDOYDSJ20P1SRpH72nA