Home > Back-end >  fs2 dropWhile with X => IO[Boolean]
fs2 dropWhile with X => IO[Boolean]

Time:11-14

I can write something like the following and it works just as it should (it yields 10):

import cats.effect.IO
import cats.effect.unsafe.implicits.global
val zz: fs2.Stream[IO, Int] = fs2.Stream.iterate[IO, Int](1)(_ 1).map(_*2)
val qq: IO[Int] = zz.dropWhile(_ < 10).take(1).compile.toList.map(_.head)
qq.unsafeRunSync()

However, supposing that, instead of a predicate like _ < 10 which returns Boolean, I have a predicate that returns an IO[Boolean]. Is there an alternative form of dropWhile which could handle this situation? I don't want to have to do something like unsafeRunSync() inside the predicate just so that it can yield a Boolean.

Clearly, this is a toy case, not the actual problem that I'm working on.

CodePudding user response:

You can easily define that combinator yourself:

def dropWhileEval[A](sa: Stream[IO, A])(p: A = IO[Boolean]): Stream[IO, A] =
  sa.evalMap(a => p(a).map(b => (b, a))).dropWhile(_._1).map(_._2)

CodePudding user response:

This answer is based on the accepted answer by @Luis Miguel Mejia Suárez. But there is a tiny typo in that answer and, essentially, I changed the question after posting the original. So here's the final (toy) code:

import cats.effect.IO
import fs2.{Pure, Stream}
import cats.effect.unsafe.implicits.global

val fLessThan10: Int => Boolean = _ < 10
val fLessThan10_lifted: IO[Int] => IO[Boolean] = _ map fLessThan10

def dropWhileEval[A](sa: Stream[IO, IO[A]])(p: IO[A] => IO[Boolean]): fStream[IO, IO[A]] =
    sa.evalMap(a => p(a).map(b => (b, a))).dropWhile(_._1).map(_._2)

val zz: Stream[IO, IO[Int]] = Stream.iterate[IO, Int](1)(_ 1).map(x => IO(x*2))
val yy: Stream[IO, IO[Int]] = dropWhileEval[Int](zz)(fLessThan10_lifted).take(1)
val result: IO[List[Int]] = yy.evalMap(identity).compile.toList
@result.unsafeRunSync()
  • Related