Skip to content

Commit

Permalink
traverse and sequence for View
Browse files Browse the repository at this point in the history
  • Loading branch information
Zschimmer committed Dec 6, 2024
1 parent 340606b commit e3fd1c4
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 1 deletion.
22 changes: 22 additions & 0 deletions js7-base/shared/src/main/scala/js7/base/utils/CatsUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,28 @@ object CatsUtils:
: G[F[B]] =
fa.traverse(f).map(_.flatten)

extension [L, R](view: View[Either[L, R]])
/** A fail-fast specialization of sequence for View: */
def sequence: Either[L, Vector[R]] =
val builder = Vector.newBuilder[R]
val it = view.iterator
while it.hasNext do
it.next() match
case Left(l) => return Left(l)
case Right(r) => builder += r
Right(builder.result())

extension [A](view: View[A])
/** A fail-fast specialization of traverse for View: */
def traverse[L, R](f: A => Either[L, R]): Either[L, Vector[R]] =
val builder = Vector.newBuilder[R]
val it = view.iterator
while it.hasNext do
f(it.next()) match
case Left(l) => return Left(l)
case Right(r) => builder += r
Right(builder.result())

extension [A](nonEmptyList: NonEmptyList[A])
def view: View[A] = nonEmptyList.toList.view

Expand Down
10 changes: 10 additions & 0 deletions js7-base/shared/src/test/scala/js7/base/problem/ProblemTest.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package js7.base.problem

import cats.syntax.semigroup.*
import cats.syntax.traverse.*
import js7.base.circeutils.CirceUtils.*
import js7.base.problem.ProblemTest.*
import js7.base.test.OurTestSuite
Expand Down Expand Up @@ -241,6 +242,15 @@ final class ProblemTest extends OurTestSuite:
case Problem.IsThrowable(_: IllegalStateException) => fail()
case _ =>

"sequence" in:
val listOfChecked = List(Right(1), Left(Problem("FIRST")), Right(2), Left(Problem("MORE")))
assert(listOfChecked.sequence == List(Left(Problem("FIRST"))))

"traverse" in:
def f(i: Int) = if i % 2 != 0 then Left(Problem(s"$i is not even")) else Right(100 * i)
val list = List(1, 2, 3, 4, 5)
assert(list.traverse(f) == Left(Problem("1 is not even")))

private def catch_(problem: Problem): String =
intercept[ProblemException] { throw problem.throwable } .toStringWithCauses

Expand Down
11 changes: 11 additions & 0 deletions js7-base/shared/src/test/scala/js7/base/utils/CatsTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package js7.base.utils

import cats.syntax.traverse.*
import js7.base.test.OurTestSuite
import js7.base.utils.ScalaUtils.syntax.*

final class CatsTest extends OurTestSuite:

"sequence" in:
val list = List(Left(1), Right(2), Left(3), Right(4))
assert(list.sequence == Left(1))
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import js7.base.catsutils.CatsEffectExtensions.joinStd
import js7.base.problem.{Problem, ProblemException}
import js7.base.test.OurAsyncTestSuite
import js7.base.utils.CatsUtils.*
import js7.base.utils.CatsUtils.syntax.traverseFlat

/**
* @author Joacim Zschimmer
Expand Down Expand Up @@ -54,6 +53,8 @@ final class CatsUtilsTest extends OurAsyncTestSuite:

"F[A]" - {
"traverseFlat(f) == traverse(f).map(_.flatten)" in:
import js7.base.utils.CatsUtils.syntax.traverseFlat

def f(i: Int): Either[String, List[Int]] =
if i < 0 then
Left("NEGATIVE")
Expand Down Expand Up @@ -83,3 +84,28 @@ final class CatsUtilsTest extends OurAsyncTestSuite:
assertDoesNotCompile("List(1, 2, 3).traverseFlat(g)")
assert(List(1, 2, 3).traverse(g).map(_.flatten) == Right(List(1, 2, 2, 3, 3, 3)))
}

"View[Either[L, R]]" - {
def f(i: Int): Either[String, Int] =
if i % 2 == 1 then Left(s"$i is not even") else Right(100 * i)

"sequence" in:
import js7.base.utils.CatsUtils.syntax.sequence

val lazyList = LazyList.from(1).map(f)
assert(lazyList.sequence == Left("1 is not even"))

val list = List(Left(1), Right(2), Left(3), Right(4))
assert(list.view.sequence == Left(1))
assert(list.sequence == Left(1))

"traverse" in:
import js7.base.utils.CatsUtils.syntax.traverse

val lazyList = LazyList.from(1)
assert(lazyList.traverse(f) == Left("1 is not even"))

val list = List(1, 2, 3, 4)
assert(list.view.traverse(f) == Left("1 is not even"))
assert(list.traverse(f) == Left("1 is not even"))
}

0 comments on commit e3fd1c4

Please sign in to comment.