Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ArraySeq instance follow-up #3302

Merged
merged 2 commits into from
Feb 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 34 additions & 5 deletions core/src/main/scala-2.13+/cats/instances/arraySeq.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package cats
package instances

import cats.data.Ior
import scala.annotation.tailrec
import scala.collection.immutable.ArraySeq
import scala.collection.mutable.Builder

trait ArraySeqInstances extends cats.kernel.instances.ArraySeqInstances {
implicit def catsStdInstancesForArraySeq: Monad[ArraySeq] with MonoidK[ArraySeq] with Traverse[ArraySeq] =
implicit def catsStdInstancesForArraySeq
: Traverse[ArraySeq] with Monad[ArraySeq] with Alternative[ArraySeq] with CoflatMap[ArraySeq] with Align[ArraySeq] =
ArraySeqInstances.stdInstances

implicit def catsStdTraverseFilterForArraySeq: TraverseFilter[ArraySeq] =
Expand All @@ -17,9 +20,14 @@ trait ArraySeqInstances extends cats.kernel.instances.ArraySeqInstances {
}
}

object ArraySeqInstances {
final private val stdInstances =
new Monad[ArraySeq] with MonoidK[ArraySeq] with Traverse[ArraySeq] {
private[cats] object ArraySeqInstances {
final private val stdInstances
: Traverse[ArraySeq] with Monad[ArraySeq] with Alternative[ArraySeq] with CoflatMap[ArraySeq] with Align[ArraySeq] =
new Traverse[ArraySeq]
with Monad[ArraySeq]
with Alternative[ArraySeq]
with CoflatMap[ArraySeq]
with Align[ArraySeq] {
def empty[A]: ArraySeq[A] =
ArraySeq.untagged.empty

Expand All @@ -38,6 +46,15 @@ object ArraySeqInstances {
def flatMap[A, B](fa: ArraySeq[A])(f: A => ArraySeq[B]): ArraySeq[B] =
fa.flatMap(f)

def coflatMap[A, B](fa: ArraySeq[A])(f: ArraySeq[A] => B): ArraySeq[B] = {
@tailrec def loop(builder: Builder[B, ArraySeq[B]], as: ArraySeq[A]): ArraySeq[B] =
as match {
case _ +: rest => loop(builder += f(as), rest)
case _ => builder.result()
}
loop(ArraySeq.untagged.newBuilder[B], fa)
}

override def map2[A, B, Z](fa: ArraySeq[A], fb: ArraySeq[B])(f: (A, B) => Z): ArraySeq[Z] =
if (fb.isEmpty) ArraySeq.empty // do O(1) work if fb is empty
else fa.flatMap(a => fb.map(b => f(a, b))) // already O(1) if fa is empty
Expand Down Expand Up @@ -138,9 +155,21 @@ object ArraySeqInstances {

override def collectFirstSome[A, B](fa: ArraySeq[A])(f: A => Option[B]): Option[B] =
fa.collectFirst(Function.unlift(f))

def functor: Functor[ArraySeq] = this

def align[A, B](fa: ArraySeq[A], fb: ArraySeq[B]): ArraySeq[Ior[A, B]] = {
val aLarger = fa.size >= fb.size
if (aLarger) {
fa.lazyZip(fb).map(Ior.both) ++ fa.drop(fb.size).map(Ior.left)
} else {
fa.lazyZip(fb).map(Ior.both) ++ fb.drop(fa.size).map(Ior.right)
}
}

}

final private val stdTraverseFilterInstance =
final private val stdTraverseFilterInstance: TraverseFilter[ArraySeq] =
new TraverseFilter[ArraySeq] {
val traverse: Traverse[ArraySeq] = stdInstances

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ trait ArraySeqInstances extends ArraySeqInstances.ArraySeqInstances1 {
}

object ArraySeqInstances {
trait ArraySeqInstances1 extends ArraySeqInstances2 {
private[instances] trait ArraySeqInstances1 extends ArraySeqInstances2 {
implicit def catsKernelStdPartialOrderForArraySeq[A: PartialOrder]: PartialOrder[ArraySeq[A]] =
new ArraySeqPartialOrder[A]

implicit def catsKernelStdHashForArraySeq[A: Hash]: Hash[ArraySeq[A]] =
new ArraySeqHash[A]
}

trait ArraySeqInstances2 {
private[instances] trait ArraySeqInstances2 {
implicit def catsKernelStdEqForArraySeq[A: Eq]: Eq[ArraySeq[A]] =
new ArraySeqEq[A]
}
Expand Down
24 changes: 19 additions & 5 deletions tests/src/test/scala-2.13+/cats/tests/ArraySeqSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@ package cats
package tests

import cats.kernel.laws.discipline.{EqTests, HashTests, MonoidTests, OrderTests, PartialOrderTests}
import cats.laws.discipline.{MonadTests, MonoidKTests, SerializableTests, TraverseFilterTests, TraverseTests}
import cats.laws.discipline.{
AlignTests,
AlternativeTests,
CoflatMapTests,
MonadTests,
SerializableTests,
TraverseFilterTests,
TraverseTests
}
import cats.laws.discipline.arbitrary._

import scala.collection.immutable.ArraySeq
Expand All @@ -14,18 +22,24 @@ class ArraySeqSuite extends CatsSuite {
checkAll("ArraySeq[Int]", OrderTests[ArraySeq[Int]].order)
checkAll("Order[ArraySeq]", SerializableTests.serializable(Order[ArraySeq[Int]]))

checkAll("ArraySeq[Int]", MonadTests[ArraySeq].monad[Int, Int, Int])
checkAll("Monad[ArraySeq]", SerializableTests.serializable(Monad[ArraySeq]))
checkAll("ArraySeq[Int]", CoflatMapTests[ArraySeq].coflatMap[Int, Int, Int])
checkAll("CoflatMap[ArraySeq]", SerializableTests.serializable(CoflatMap[ArraySeq]))

checkAll("ArraySeq[Int]", MonoidKTests[ArraySeq].monoidK[Int])
checkAll("MonoidK[ArraySeq]", SerializableTests.serializable(MonoidK[ArraySeq]))
checkAll("ArraySeq[Int]", AlternativeTests[ArraySeq].alternative[Int, Int, Int])
checkAll("Alternative[ArraySeq]", SerializableTests.serializable(Alternative[ArraySeq]))

checkAll("ArraySeq[Int] with Option", TraverseTests[ArraySeq].traverse[Int, Int, Int, Set[Int], Option, Option])
checkAll("Traverse[ArraySeq]", SerializableTests.serializable(Traverse[ArraySeq]))

checkAll("ArraySeq[Int]", MonadTests[ArraySeq].monad[Int, Int, Int])
checkAll("Monad[ArraySeq]", SerializableTests.serializable(Monad[ArraySeq]))

checkAll("ArraySeq[Int]", TraverseFilterTests[ArraySeq].traverseFilter[Int, Int, Int])
checkAll("TraverseFilter[ArraySeq]", SerializableTests.serializable(TraverseFilter[ArraySeq]))

checkAll("ArraySeq[Int]", AlignTests[ArraySeq].align[Int, Int, Int, Int])
checkAll("Align[ArraySeq]", SerializableTests.serializable(Align[ArraySeq]))

{
implicit val eqv: Eq[ListWrapper[Int]] = ListWrapper.eqv[Int]
checkAll("ArraySeq[Int]", EqTests[ArraySeq[ListWrapper[Int]]].eqv)
Expand Down