Skip to content

Commit

Permalink
ArraySeq instance follow-up (#3302)
Browse files Browse the repository at this point in the history
* Add Align, CoflatMap, and Alternative instances for ArraySeq

* Avoid ArraySeq prioritization traits in public API
  • Loading branch information
travisbrown authored Feb 18, 2020
1 parent e6e24fc commit 8126941
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 12 deletions.
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

0 comments on commit 8126941

Please sign in to comment.