the former is more flexible, although it is likely that only Kleisli
has a WithRun
instance i'm guessing.
it's a familiarity issue, like you said. i think more folks would understand the Kleisli
version since it is more "concrete"
there's the evalMap(f: A => F[B]): Resource[F, A] => Resource[F, B] = _.flatMap(a => Resource.liftF(f(a)))
combinator that lifts the output of f
into an "inner" Resource
.
what about a different combinator that uses the first Resource
to create the next, where the first can be released: evalUse(f: A => F[B]): Resource[F, A] => Resource[F, B] = rfa => Resource.liftF(rfa.use(f))
?
def multiRace[F[_]: Concurrent, A](fas: List[F[A]]): F[A] = {
def spawn[B](fa: F[B]): Resource[F, Unit] =
Resource.make(fa.start)(_.cancel).void
def finish(fa: F[A], d: Deferred[F, Either[Throwable, A]]): F[Unit] =
fa.attempt.flatMap(d.complete)
Deferred[F, Either[Throwable, A]]
.flatMap { result =>
fas
.traverse(fa => spawn(finish(fa, result)))
.use(_ => result.get.rethrow)
}
}
def program(i: Int) = {
for {
wait <- IO(scala.util.Random.nextInt(1000))
_ <- IO(println(s"program $i waiting for $wait millis"))
_ <- IO.sleep(wait.millis)
_ <- IO(println(s"program $i finished"))
} yield i
}.guarantee(IO(println(s"program $i finalised")))
def test = multiRace(List.range(0, 5).map(program)).unsafeRunSync
ConcurrentEffect
for IorT
or am I missing something?
raceN
: https://gist.github.com/ChristopherDavenport/f75012bc89a7b7871f56fd14bf906d5f
IO
right? and now all calling functions must return some form of IO[F]
or a monad transformer or something (when say previously they just returned an Option
or something)
Like, if I have a bunch of nested functions, and one deeply nested function wants to get command line input or something, that function needs to return an
IO
right? and now all calling functions must return some form ofIO[F]
or a monad transformer or something (when say previously they just returned anOption
or something)
LiftIO
basically solves that problem. If you have a LiftIO[F]
, then even if you have something that concretely returns an IO[A]
, you can get an F[A]
out of it.
Also on another note, what is
F
actually termed as, as it's used in the cats documentation? a container? a single holed type? or something else?
:-) Usually we use A
for something like IO[A]
, since we often use F
in the context of F[A]
or similar. And to answer your question, it's usually termed "the value", even though that may not be precisely accurate