Skip to content

Commit

Permalink
override prependK/appendK for NE-wrappers of std containers
Browse files Browse the repository at this point in the history
  • Loading branch information
satorg committed Nov 4, 2021
1 parent fb591ce commit 3f7c9bf
Show file tree
Hide file tree
Showing 11 changed files with 174 additions and 104 deletions.
2 changes: 1 addition & 1 deletion core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ sealed abstract private[data] class NonEmptyLazyListInstances extends NonEmptyLa

implicit val catsDataInstancesForNonEmptyLazyList: Bimonad[NonEmptyLazyList]
with NonEmptyTraverse[NonEmptyLazyList]
with SemigroupK[NonEmptyLazyList]
with NonEmptyAlternative[NonEmptyLazyList]
with Align[NonEmptyLazyList] =
new AbstractNonEmptyInstances[LazyList, NonEmptyLazyList] with Align[NonEmptyLazyList] {

Expand Down
14 changes: 10 additions & 4 deletions core/src/main/scala/cats/data/AbstractNonEmptyInstances.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,23 @@ abstract private[data] class AbstractNonEmptyInstances[F[_], NonEmptyF[_]](impli
MF: Monad[F],
CF: CoflatMap[F],
TF: Traverse[F],
SF: SemigroupK[F]
SF: Alternative[F]
) extends Bimonad[NonEmptyF]
with NonEmptyTraverse[NonEmptyF]
with SemigroupK[NonEmptyF] {
with NonEmptyAlternative[NonEmptyF] {
val monadInstance = MF.asInstanceOf[Monad[NonEmptyF]]
val coflatMapInstance = CF.asInstanceOf[CoflatMap[NonEmptyF]]
val traverseInstance = Traverse[F].asInstanceOf[Traverse[NonEmptyF]]
val semiGroupKInstance = SemigroupK[F].asInstanceOf[SemigroupK[NonEmptyF]]
val alternativeInstance = Alternative[F].asInstanceOf[Alternative[NonEmptyF]]

def combineK[A](a: NonEmptyF[A], b: NonEmptyF[A]): NonEmptyF[A] =
semiGroupKInstance.combineK(a, b)
alternativeInstance.combineK(a, b)

override def prependK[A](a: A, fa: NonEmptyF[A]): NonEmptyF[A] =
alternativeInstance.prependK(a, fa)

override def appendK[A](fa: NonEmptyF[A], a: A): NonEmptyF[A] =
alternativeInstance.appendK(fa, a)

def pure[A](x: A): NonEmptyF[A] = monadInstance.pure(x)

Expand Down
10 changes: 9 additions & 1 deletion core/src/main/scala/cats/data/NonEmptyChain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -586,10 +586,18 @@ class NonEmptyChainOps[A](private val value: NonEmptyChain[A])

sealed abstract private[data] class NonEmptyChainInstances extends NonEmptyChainInstances1 {

implicit val catsDataInstancesForNonEmptyChain: SemigroupK[NonEmptyChain]
// TODO: put correct version number.
@deprecated("Use catsDataInstancesForNonEmptyListBinCompat1", "2.6.2-?")
def catsDataInstancesForNonEmptyChain: SemigroupK[NonEmptyChain]
with NonEmptyTraverse[NonEmptyChain]
with Bimonad[NonEmptyChain]
with Align[NonEmptyChain] =
catsDataInstancesForNonEmptyChainBinCompat1

implicit val catsDataInstancesForNonEmptyChainBinCompat1: Align[NonEmptyChain]
with Bimonad[NonEmptyChain]
with NonEmptyAlternative[NonEmptyChain]
with NonEmptyTraverse[NonEmptyChain] =
new AbstractNonEmptyInstances[Chain, NonEmptyChain] with Align[NonEmptyChain] {
def extract[A](fa: NonEmptyChain[A]): A = fa.head

Expand Down
22 changes: 18 additions & 4 deletions core/src/main/scala/cats/data/NonEmptyList.scala
Original file line number Diff line number Diff line change
Expand Up @@ -712,23 +712,37 @@ object NonEmptyList extends NonEmptyListInstances {

sealed abstract private[data] class NonEmptyListInstances extends NonEmptyListInstances0 {

// TODO: put correct version number.
@deprecated("Use catsDataInstancesForNonEmptyListBinCompat1", "2.6.2-?")
def catsDataInstancesForNonEmptyList
: SemigroupK[NonEmptyList] with Bimonad[NonEmptyList] with NonEmptyTraverse[NonEmptyList] with Align[NonEmptyList] =
catsDataInstancesForNonEmptyListBinCompat1

/**
* This is not a bug. The declared type of `catsDataInstancesForNonEmptyList` intentionally ignores
* `NonEmptyReducible` trait for it not being a typeclass.
*
* Also see the discussion: PR #3541 and issue #3069.
*/
implicit val catsDataInstancesForNonEmptyList
: SemigroupK[NonEmptyList] with Bimonad[NonEmptyList] with NonEmptyTraverse[NonEmptyList] with Align[NonEmptyList] =
implicit val catsDataInstancesForNonEmptyListBinCompat1: NonEmptyAlternative[NonEmptyList]
with Bimonad[NonEmptyList]
with NonEmptyTraverse[NonEmptyList]
with Align[NonEmptyList] =
new NonEmptyReducible[NonEmptyList, List]
with SemigroupK[NonEmptyList]
with NonEmptyAlternative[NonEmptyList]
with Bimonad[NonEmptyList]
with NonEmptyTraverse[NonEmptyList]
with Align[NonEmptyList] {

def combineK[A](a: NonEmptyList[A], b: NonEmptyList[A]): NonEmptyList[A] =
a.concatNel(b)

override def prependK[A](a: A, fa: NonEmptyList[A]): NonEmptyList[A] =
fa.prepend(a)

override def appendK[A](fa: NonEmptyList[A], a: A): NonEmptyList[A] =
fa.append(a)

override def split[A](fa: NonEmptyList[A]): (A, List[A]) = (fa.head, fa.tail)

override def reduceLeft[A](fa: NonEmptyList[A])(f: (A, A) => A): A =
Expand Down Expand Up @@ -868,7 +882,7 @@ sealed abstract private[data] class NonEmptyListInstances extends NonEmptyListIn
new NonEmptyParallel[NonEmptyList] {
type F[x] = ZipNonEmptyList[x]

def flatMap: FlatMap[NonEmptyList] = NonEmptyList.catsDataInstancesForNonEmptyList
def flatMap: FlatMap[NonEmptyList] = NonEmptyList.catsDataInstancesForNonEmptyListBinCompat1

def apply: Apply[ZipNonEmptyList] = ZipNonEmptyList.catsDataCommutativeApplyForZipNonEmptyList

Expand Down
24 changes: 19 additions & 5 deletions core/src/main/scala/cats/data/NonEmptySeq.scala
Original file line number Diff line number Diff line change
Expand Up @@ -350,23 +350,37 @@ final class NonEmptySeq[+A] private (val toSeq: Seq[A]) extends AnyVal with NonE
@suppressUnusedImportWarningForScalaVersionSpecific
sealed abstract private[data] class NonEmptySeqInstances {

// TODO: put correct version number.
@deprecated("Use catsDataInstancesForNonEmptyListBinCompat1", "2.6.2-?")
def catsDataInstancesForNonEmptySeq
: SemigroupK[NonEmptySeq] with Bimonad[NonEmptySeq] with NonEmptyTraverse[NonEmptySeq] with Align[NonEmptySeq] =
catsDataInstancesForNonEmptySeqBinCompat1

/**
* This is not a bug. The declared type of `catsDataInstancesForNonEmptySeq` intentionally ignores
* `NonEmptyReducible` trait for it not being a typeclass.
*
* Also see the discussion: PR #3541 and issue #3069.
*/
implicit val catsDataInstancesForNonEmptySeq
: SemigroupK[NonEmptySeq] with Bimonad[NonEmptySeq] with NonEmptyTraverse[NonEmptySeq] with Align[NonEmptySeq] =
implicit val catsDataInstancesForNonEmptySeqBinCompat1: NonEmptyAlternative[NonEmptySeq]
with Bimonad[NonEmptySeq]
with NonEmptyTraverse[NonEmptySeq]
with Align[NonEmptySeq] =
new NonEmptyReducible[NonEmptySeq, Seq]
with SemigroupK[NonEmptySeq]
with NonEmptyAlternative[NonEmptySeq]
with Bimonad[NonEmptySeq]
with NonEmptyTraverse[NonEmptySeq]
with Align[NonEmptySeq] {

def combineK[A](a: NonEmptySeq[A], b: NonEmptySeq[A]): NonEmptySeq[A] =
a.concatNeSeq(b)

override def prependK[A](a: A, fa: NonEmptySeq[A]): NonEmptySeq[A] =
fa.prepend(a)

override def appendK[A](fa: NonEmptySeq[A], a: A): NonEmptySeq[A] =
fa.append(a)

override def split[A](fa: NonEmptySeq[A]): (A, Seq[A]) = (fa.head, fa.tail)

override def size[A](fa: NonEmptySeq[A]): Long = fa.length.toLong
Expand Down Expand Up @@ -502,14 +516,14 @@ sealed abstract private[data] class NonEmptySeqInstances {
Show.show[NonEmptySeq[A]](_.show)

implicit def catsDataSemigroupForNonEmptySeq[A]: Semigroup[NonEmptySeq[A]] =
catsDataInstancesForNonEmptySeq.algebra
catsDataInstancesForNonEmptySeqBinCompat1.algebra

implicit def catsDataParallelForNonEmptySeq: NonEmptyParallel.Aux[NonEmptySeq, ZipNonEmptySeq] =
new NonEmptyParallel[NonEmptySeq] {
type F[x] = ZipNonEmptySeq[x]

def apply: Apply[ZipNonEmptySeq] = ZipNonEmptySeq.catsDataCommutativeApplyForZipNonEmptySeq
def flatMap: FlatMap[NonEmptySeq] = NonEmptySeq.catsDataInstancesForNonEmptySeq
def flatMap: FlatMap[NonEmptySeq] = NonEmptySeq.catsDataInstancesForNonEmptySeqBinCompat1

def sequential: ZipNonEmptySeq ~> NonEmptySeq =
new (ZipNonEmptySeq ~> NonEmptySeq) { def apply[A](a: ZipNonEmptySeq[A]): NonEmptySeq[A] = a.value }
Expand Down
22 changes: 18 additions & 4 deletions core/src/main/scala/cats/data/NonEmptyVector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -350,25 +350,39 @@ final class NonEmptyVector[+A] private (val toVector: Vector[A])
@suppressUnusedImportWarningForScalaVersionSpecific
sealed abstract private[data] class NonEmptyVectorInstances {

// TODO: put correct version number.
@deprecated("Use catsDataInstancesForNonEmptyListBinCompat1", "2.6.2-?")
def catsDataInstancesForNonEmptyVector: SemigroupK[NonEmptyVector]
with Bimonad[NonEmptyVector]
with NonEmptyTraverse[NonEmptyVector]
with Align[NonEmptyVector] =
catsDataInstancesForNonEmptyVectorBinCompat1

/**
* This is not a bug. The declared type of `catsDataInstancesForNonEmptyVector` intentionally ignores
* `NonEmptyReducible` trait for it not being a typeclass.
*
* Also see the discussion: PR #3541 and issue #3069.
*/
implicit val catsDataInstancesForNonEmptyVector: SemigroupK[NonEmptyVector]
implicit val catsDataInstancesForNonEmptyVectorBinCompat1: NonEmptyAlternative[NonEmptyVector]
with Bimonad[NonEmptyVector]
with NonEmptyTraverse[NonEmptyVector]
with Align[NonEmptyVector] =
new NonEmptyReducible[NonEmptyVector, Vector]
with SemigroupK[NonEmptyVector]
with NonEmptyAlternative[NonEmptyVector]
with Bimonad[NonEmptyVector]
with NonEmptyTraverse[NonEmptyVector]
with Align[NonEmptyVector] {

def combineK[A](a: NonEmptyVector[A], b: NonEmptyVector[A]): NonEmptyVector[A] =
a.concatNev(b)

override def prependK[A](a: A, fa: NonEmptyVector[A]): NonEmptyVector[A] =
fa.prepend(a)

override def appendK[A](fa: NonEmptyVector[A], a: A): NonEmptyVector[A] =
fa.append(a)

override def split[A](fa: NonEmptyVector[A]): (A, Vector[A]) = (fa.head, fa.tail)

override def size[A](fa: NonEmptyVector[A]): Long = fa.length.toLong
Expand Down Expand Up @@ -504,14 +518,14 @@ sealed abstract private[data] class NonEmptyVectorInstances {
Show.show[NonEmptyVector[A]](_.show)

implicit def catsDataSemigroupForNonEmptyVector[A]: Semigroup[NonEmptyVector[A]] =
catsDataInstancesForNonEmptyVector.algebra
catsDataInstancesForNonEmptyVectorBinCompat1.algebra

implicit def catsDataParallelForNonEmptyVector: NonEmptyParallel.Aux[NonEmptyVector, ZipNonEmptyVector] =
new NonEmptyParallel[NonEmptyVector] {
type F[x] = ZipNonEmptyVector[x]

def apply: Apply[ZipNonEmptyVector] = ZipNonEmptyVector.catsDataCommutativeApplyForZipNonEmptyVector
def flatMap: FlatMap[NonEmptyVector] = NonEmptyVector.catsDataInstancesForNonEmptyVector
def flatMap: FlatMap[NonEmptyVector] = NonEmptyVector.catsDataInstancesForNonEmptyVectorBinCompat1

def sequential: ZipNonEmptyVector ~> NonEmptyVector =
new (ZipNonEmptyVector ~> NonEmptyVector) { def apply[A](a: ZipNonEmptyVector[A]): NonEmptyVector[A] = a.value }
Expand Down
33 changes: 16 additions & 17 deletions tests/src/test/scala-2.13+/cats/tests/NonEmptyLazyListSuite.scala
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
package cats.tests

import cats.{Align, Bimonad, SemigroupK, Show, Traverse}
import cats.data.{NonEmptyLazyList, NonEmptyLazyListOps, NonEmptyVector}
import cats.kernel.{Eq, Hash, Order, PartialOrder, Semigroup}
import cats.kernel.laws.discipline.{EqTests, HashTests, OrderTests, PartialOrderTests, SemigroupTests}
import cats.laws.discipline.{
AlignTests,
BimonadTests,
NonEmptyTraverseTests,
SemigroupKTests,
SerializableTests,
ShortCircuitingTests
}
import cats._
import cats.data.NonEmptyLazyList
import cats.data.NonEmptyLazyListOps
import cats.data.NonEmptyVector
import cats.kernel.laws.discipline.EqTests
import cats.kernel.laws.discipline.HashTests
import cats.kernel.laws.discipline.OrderTests
import cats.kernel.laws.discipline.PartialOrderTests
import cats.kernel.laws.discipline.SemigroupTests
import cats.kernel.laws.discipline.SerializableTests
import cats.laws.discipline._
import cats.laws.discipline.arbitrary._
import cats.syntax.either._
import cats.syntax.foldable._
import cats.syntax.eq._
import cats.Reducible
import cats.Eval
import cats.syntax.foldable._
import org.scalacheck.Prop._

class NonEmptyLazyListSuite extends NonEmptyCollectionSuite[LazyList, NonEmptyLazyList, NonEmptyLazyListOps] {
Expand All @@ -31,8 +28,10 @@ class NonEmptyLazyListSuite extends NonEmptyCollectionSuite[LazyList, NonEmptyLa
checkAll(s"NonEmptyLazyList[Int]", HashTests[NonEmptyLazyList[Int]].hash)
checkAll(s"Hash[NonEmptyLazyList[Int]]", SerializableTests.serializable(Hash[NonEmptyLazyList[Int]]))

checkAll("NonEmptyLazyList[Int]", SemigroupKTests[NonEmptyLazyList].semigroupK[Int])
checkAll("SemigroupK[NonEmptyLazyList]", SerializableTests.serializable(SemigroupK[NonEmptyLazyList]))
checkAll("NonEmptyLazyList[Int]", NonEmptyAlternativeTests[NonEmptyLazyList].nonEmptyAlternative[Int, Int, Int])
checkAll("NonEmptyAlternative[NonEmptyLazyList]",
SerializableTests.serializable(NonEmptyAlternative[NonEmptyLazyList])
)

checkAll("NonEmptyLazyList[Int] with Option",
NonEmptyTraverseTests[NonEmptyLazyList].nonEmptyTraverse[Option, Int, Int, Int, Int, Option, Option]
Expand Down
27 changes: 12 additions & 15 deletions tests/src/test/scala/cats/tests/NonEmptyChainSuite.scala
Original file line number Diff line number Diff line change
@@ -1,30 +1,27 @@
package cats.tests

import cats.{Align, Bimonad, SemigroupK, Show, Traverse}
import cats.data.{Chain, NonEmptyChain, NonEmptyChainOps}
import cats.kernel.{Eq, Order, PartialOrder, Semigroup}
import cats.kernel.laws.discipline.{EqTests, OrderTests, PartialOrderTests, SemigroupTests}
import cats.laws.discipline.{
AlignTests,
BimonadTests,
NonEmptyTraverseTests,
SemigroupKTests,
SerializableTests,
ShortCircuitingTests
}
import cats._
import cats.data.Chain
import cats.data.NonEmptyChain
import cats.data.NonEmptyChainOps
import cats.kernel.laws.discipline.EqTests
import cats.kernel.laws.discipline.OrderTests
import cats.kernel.laws.discipline.PartialOrderTests
import cats.kernel.laws.discipline.SemigroupTests
import cats.laws.discipline._
import cats.laws.discipline.arbitrary._
import cats.syntax.either._
import cats.syntax.foldable._
import cats.syntax.eq._
import cats.syntax.foldable._
import org.scalacheck.Prop._

class NonEmptyChainSuite extends NonEmptyCollectionSuite[Chain, NonEmptyChain, NonEmptyChainOps] {
protected def toList[A](value: NonEmptyChain[A]): List[A] = value.toChain.toList
protected def underlyingToList[A](underlying: Chain[A]): List[A] = underlying.toList
protected def toNonEmptyCollection[A](nea: NonEmptyChain[A]): NonEmptyChainOps[A] = nea

checkAll("NonEmptyChain[Int]", SemigroupKTests[NonEmptyChain].semigroupK[Int])
checkAll("SemigroupK[NonEmptyChain]", SerializableTests.serializable(SemigroupK[NonEmptyChain]))
checkAll("NonEmptyChain[Int]", NonEmptyAlternativeTests[NonEmptyChain].nonEmptyAlternative[Int, Int, Int])
checkAll("NonEmptyAlternative[NonEmptyChain]", SerializableTests.serializable(NonEmptyAlternative[NonEmptyChain]))

checkAll("NonEmptyChain[Int] with Option",
NonEmptyTraverseTests[NonEmptyChain].nonEmptyTraverse[Option, Int, Int, Int, Int, Option, Option]
Expand Down
34 changes: 16 additions & 18 deletions tests/src/test/scala/cats/tests/NonEmptyListSuite.scala
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
package cats.tests

import cats.{Align, Bimonad, Eval, NonEmptyTraverse, Now, Reducible, SemigroupK, Show}
import cats.data.{NonEmptyList, NonEmptyMap, NonEmptySet, NonEmptyVector}
import cats._
import cats.data.NonEmptyList
import cats.data.NonEmptyList.ZipNonEmptyList
import cats.kernel.{Eq, Order, PartialOrder, Semigroup}
import cats.kernel.laws.discipline.{EqTests, OrderTests, PartialOrderTests, SemigroupTests}
import cats.data.NonEmptyMap
import cats.data.NonEmptySet
import cats.data.NonEmptyVector
import cats.kernel.laws.discipline.EqTests
import cats.kernel.laws.discipline.OrderTests
import cats.kernel.laws.discipline.PartialOrderTests
import cats.kernel.laws.discipline.SemigroupTests
import cats.laws.discipline._
import cats.laws.discipline.arbitrary._
import cats.laws.discipline.{
AlignTests,
BimonadTests,
CommutativeApplyTests,
NonEmptyTraverseTests,
ReducibleTests,
SemigroupKTests,
SerializableTests,
ShortCircuitingTests
}
import cats.syntax.eq._
import cats.syntax.foldable._
import cats.syntax.reducible._
import cats.syntax.show._
import scala.collection.immutable.{SortedMap, SortedSet}
import cats.syntax.eq._
import org.scalacheck.Prop._
import org.scalacheck.Test.Parameters

import scala.collection.immutable.SortedMap
import scala.collection.immutable.SortedSet

class NonEmptyListSuite extends NonEmptyCollectionSuite[List, NonEmptyList, NonEmptyList] {
protected def toList[A](value: NonEmptyList[A]): List[A] = value.toList
protected def underlyingToList[A](underlying: List[A]): List[A] = underlying
Expand All @@ -43,8 +41,8 @@ class NonEmptyListSuite extends NonEmptyCollectionSuite[List, NonEmptyList, NonE
checkAll("NonEmptyList[Int]", ReducibleTests[NonEmptyList].reducible[Option, Int, Int])
checkAll("Reducible[NonEmptyList]", SerializableTests.serializable(Reducible[NonEmptyList]))

checkAll("NonEmptyList[Int]", SemigroupKTests[NonEmptyList].semigroupK[Int])
checkAll("SemigroupK[NonEmptyList[A]]", SerializableTests.serializable(SemigroupK[NonEmptyList]))
checkAll("NonEmptyList[Int]", NonEmptyAlternativeTests[NonEmptyList].nonEmptyAlternative[Int, Int, Int])
checkAll("NonEmptyAlternative[NonEmptyList[A]]", SerializableTests.serializable(NonEmptyAlternative[NonEmptyList]))

checkAll("NonEmptyList[Int]", SemigroupTests[NonEmptyList[Int]].semigroup)
checkAll("Semigroup[NonEmptyList[Int]]", SerializableTests.serializable(Semigroup[NonEmptyList[Int]]))
Expand Down
Loading

0 comments on commit 3f7c9bf

Please sign in to comment.