scalaexistsscala-catscats-effectfindfirst

How to return upon encountering first "true" in a List[IO[Boolean]] in Scala Cats Effect


Say I have a set of rules that have a validation function that returns IO[Boolean] at runtime.

case class Rule1() {
  def validate(): IO[Boolean] = IO.pure(false)
}
case class Rule2() {
  def validate(): IO[Boolean] = IO.pure(false)
}
case class Rule3() {
  def validate(): IO[Boolean] = IO.pure(true)
}

val rules = List(Rule1(), Rule2(), Rule3())

Now I have to iterate through these rules and see "if any of these rules" hold valid and if not then throw exception!

for {
  i <- rules.map(_.validate()).sequence
  _ <- if (i.contains(true)) IO.unit else IO.raiseError(new RuntimeException("Failed"))
} yield ()

The problem with the code snippet above is that it is trying to evaluate all the rules! What I really want is to exit at the encounter of the first true validation.

Not sure how to achieve this using cats effects in Scala.


Solution

  • I claim that existsM is the most direct way to achieve what you want. It behaves pretty much the same as exists, but for monadic predicates:

    for {
      t <- rules.existsM(_.validate())
      _ <- IO.raiseUnless(t)(new RuntimeException("Failed"))
    } yield ()
    

    It also stops the search as soon as it finds the first true.

    The raiseUnless is just some syntactic sugar that's equivalent to the if-else from your question.