Skip to content

Commit

Permalink
improve the type specificity of the syntax extensions; implement test…
Browse files Browse the repository at this point in the history
… for .toNes
  • Loading branch information
vreuter committed Oct 28, 2024
1 parent 8e8fbda commit 79e6828
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 12 deletions.
24 changes: 13 additions & 11 deletions modules/pan/src/main/scala/collections.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package at.ac.oeaw.imba.gerlich.gerlib

import scala.collection.immutable.SortedSet
import cats.*
import cats.data.{NonEmptyList, NonEmptySet}
import io.github.iltotore.iron.{:|, Constraint, refineEither, refineUnsafe}
Expand Down Expand Up @@ -95,10 +96,20 @@ object collections:
infix def +(x: X): AtLeast2Set[X] =
(xs + x).refineUnsafe[MinLength[2]]

/** With knowledge that the given container type is an set, we can use the underlying
* collection's {@code .contains} member.
*
* @return
* Whether the underlying collection contains the given element
*/
def contains(x: X): Boolean = (xs: Set[X]).contains(x)

/** Convert safely to [[cats.data.NonEmptySet]]. */
def toNes(using ord: Order[X]): NonEmptySet[X] =
val sorted = scala.collection.immutable.SortedSet.from(xs)(ord.toOrdering)
NonEmptySet.fromSetUnsafe(sorted)
NonEmptySet.fromSetUnsafe(xs.toSortedSet)

def toSortedSet(using ord: Order[X]): SortedSet[X] =
SortedSet.from(xs)(ord.toOrdering)

extension [X](xs: AtLeast2List[X])
/** With knowledge that the given container type is an set, we can use the underlying
Expand All @@ -115,15 +126,6 @@ object collections:
/** We can safely convert to [[cats.data.NonEmptyList]]. */
def toNel: NonEmptyList[X] = NonEmptyList(xs.head, xs.tail)

extension [C[*] <: Set[*], X](xs: AtLeast2[C, X])
/** With knowledge that the given container type is an set, we can use the underlying
* collection's {@code .contains} member.
*
* @return
* Whether the underlying collection contains the given element
*/
def contains(x: X): Boolean = (xs: C[X]).contains(x)

extension [C[*], X](xs: AtLeast2[C, X])
/** When the underlying container type has a functor, use it to {@code .map} over the
* refined collection.
Expand Down
13 changes: 12 additions & 1 deletion modules/pan/src/test/scala/TestAtLeast2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ class TestAtLeast2
checkAll("AtLeast2[Set, *].SemigroupLaws", SemigroupKTests[AtLeast2Set].semigroupK[Int])

test("When syntax is imported, AtLeast2[Set, A] may be represented as cats.data.NonEmptySet[A]."):
pending
assertCompiles("AtLeast2.unsafe(Set(1, 2))") // Precondition: we can build the collection.
assertTypeError(
"AtLeast2.unsafe(Set(1, 2)).toNes"
) // Test: without syntax import, .toNes is unavailable.
assertCompiles(
"import AtLeast2.syntax.toNes; AtLeast2.unsafe(Set(1, 2)).toNes"
) // Test: with syntax import, .toNes becomes available.

// Check the equivalence of the result of the .toNes operation and the underlying collection.
import AtLeast2.syntax.{toNes, toSortedSet}
forAll: (xs: AtLeast2[Set, Int]) =>
xs.toNes shouldEqual NonEmptySet.fromSetUnsafe(xs.toSortedSet)

end TestAtLeast2

0 comments on commit 79e6828

Please sign in to comment.