Closed Jasper-M closed 1 month ago
Interesting, that must be because of the void(...)
in the Applicative#whenA
implementation? We avoid that b/c we require that the argument is already voided.
See also:
We could do that, but this slimmed down version still takes 20 seconds to complete on my machine. And that's in the happy path where it doesn't fail or use a ridiculous amount of memory.
def loop(i: Long): IO[Unit] =
IO.unit >> IO.whenA(i < 1_100_000_000)(loop(i + 1))
Interesting, that must be because of the
void(...)
in theApplicative#whenA
implementation?
Should We do something about IO.void
, ex:
def void: IO[Unit] =
5 - map(_ => ())
6 + isInstanceOf[IO[Unit]] match {
7 + case true => this.asInstanceOf[IO[Unit]]
8 + case _ => map(_ => ())
9 + }
isInstanceOf[IO[Unit]]
@lenguyenthanh Unfortunately this won't work because type parameters are erased at runtime, so it will always be true
.
Can you add an override in the
Async
typeclass implementation for both methods as well? That will allow the optimization to work in polymorphic contexts.
The problem is like @armanbilge pointed out that the typeclass method takes a => F[A]
whereas the IO
method takes => IO[Unit]
. So I don't think you can do any better than if (cond) void(f) else unit
in the typeclass. Maybe the method signature in cats-core should be fixed, but that seems hard to do without breaking things.
Both because the signature in Cats is definitely wrong
This might be a matter of opinion, see a discussion on this topic in https://github.com/typelevel/cats/pull/4352#discussion_r1028533867.
I noticed that this simple recursive loop
ends with
While the equivalent
if else
code seems to keep running without noticeable GC pauses.