Skip to content

Commit

Permalink
Add DistributiveLattice instance for HashSet
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidGregory084 committed Aug 2, 2022
1 parent 462709e commit aaa8a0a
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 11 deletions.
36 changes: 28 additions & 8 deletions core/src/main/scala/cats/collections/HashSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@

package cats.collections

import algebra.lattice.DistributiveLattice
import cats.Foldable
import cats.Show
import cats.UnorderedFoldable
Expand Down Expand Up @@ -1108,7 +1109,7 @@ object HashSet extends compat.HashSetCompatCompanion {
}
}

implicit val catsDataUnorderedFoldableForHashSet: UnorderedFoldable[HashSet] =
implicit val catsCollectionsUnorderedFoldableForHashSet: UnorderedFoldable[HashSet] =
new UnorderedFoldable[HashSet] {
override def isEmpty[A](fa: HashSet[A]): Boolean = fa.isEmpty

Expand All @@ -1127,18 +1128,37 @@ object HashSet extends compat.HashSetCompatCompanion {
C.combineAll(fa.iterator.map(f))
}

implicit def catsDataCommutativeMonoidForHashSet[A](implicit hash: Hash[A]): CommutativeMonoid[HashSet[A]] =
new CommutativeMonoid[HashSet[A]] {
def empty: HashSet[A] = HashSet.empty[A]
def combine(x: HashSet[A], y: HashSet[A]): HashSet[A] = x.union(y)
}
implicit def catsCollectionsCommutativeMonoidForHashSet[A](implicit hash: Hash[A]): CommutativeMonoid[HashSet[A]] =
new HashSetUnionMonoid[A]

implicit def catsDataShowForHashSet[A](implicit A: Show[A]): Show[HashSet[A]] =
implicit def catsCollectionsShowForHashSet[A](implicit A: Show[A]): Show[HashSet[A]] =
Show.show[HashSet[A]](_.show)

implicit def catsDataHashForHashSet[A](implicit A: Hash[A]): Hash[HashSet[A]] =
implicit def catsCollectionsHashForHashSet[A](implicit A: Hash[A]): Hash[HashSet[A]] =
new Hash[HashSet[A]] {
def hash(hs: HashSet[A]): Int = hs.hashCode
def eqv(x: HashSet[A], y: HashSet[A]): Boolean = x === y
}

implicit def catsCollectionsDistributiveLatticeForHashSet[A](implicit A: Hash[A]): DistributiveLattice[HashSet[A]] =
new DistributiveLattice[HashSet[A]] {
private val joinMonoid = new HashSetUnionMonoid[A]
private val meetMonoid = new HashSetIntersectionMonoid[A]

override def join(lhs: HashSet[A], rhs: HashSet[A]): HashSet[A] =
joinMonoid.combine(lhs, rhs)

override def meet(lhs: HashSet[A], rhs: HashSet[A]): HashSet[A] =
meetMonoid.combine(lhs, rhs)
}
}

class HashSetUnionMonoid[A: Hash] extends CommutativeMonoid[HashSet[A]] {
override def empty: HashSet[A] = HashSet.empty[A]
override def combine(x: HashSet[A], y: HashSet[A]): HashSet[A] = x.union(y)
}

class HashSetIntersectionMonoid[A: Hash] extends CommutativeMonoid[HashSet[A]] {
override def empty: HashSet[A] = HashSet.empty[A]
override def combine(x: HashSet[A], y: HashSet[A]): HashSet[A] = x.intersect(y)
}
16 changes: 13 additions & 3 deletions tests/src/test/scala/cats/collections/HashSetSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

package cats.collections

import algebra.laws.LatticeLaws
import cats.collections.arbitrary.hashset._
import cats.kernel.laws.discipline.CommutativeMonoidTests
import cats.kernel.laws.discipline.HashTests
Expand All @@ -41,14 +42,23 @@ class HashSetSuite extends DisciplineSuite {
DefaultScalaCheckPropertyCheckConfig.default

checkAll("HashSet[Int]", HashTests[HashSet[Int]].hash)
checkAll("Hash[HashSet[Int]]", SerializableTests.serializable(HashSet.catsDataHashForHashSet[Int]))
checkAll("Hash[HashSet[Int]]", SerializableTests.serializable(HashSet.catsCollectionsHashForHashSet[Int]))

checkAll("HashSet[Int]", UnorderedFoldableTests[HashSet].unorderedFoldable[Int, Int])
checkAll("UnorderedFoldable[HashSet]", SerializableTests.serializable(HashSet.catsDataUnorderedFoldableForHashSet))
checkAll("UnorderedFoldable[HashSet]",
SerializableTests.serializable(HashSet.catsCollectionsUnorderedFoldableForHashSet)
)

checkAll("HashSet[String]", CommutativeMonoidTests[HashSet[String]].commutativeMonoid)

checkAll("CommutativeMonoid[HashSet[String]]",
SerializableTests.serializable(HashSet.catsDataCommutativeMonoidForHashSet[String])
SerializableTests.serializable(HashSet.catsCollectionsCommutativeMonoidForHashSet[String])
)

checkAll("HashSet[String]", LatticeLaws[HashSet[String]].distributiveLattice)

checkAll("DistributiveLattice[HashSet[String]]",
SerializableTests.serializable(HashSet.catsCollectionsDistributiveLatticeForHashSet[String])
)

// Based on https://stackoverflow.com/questions/9406775/why-does-string-hashcode-in-java-have-many-conflicts
Expand Down

0 comments on commit aaa8a0a

Please sign in to comment.