Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Sep 05 2019 14:43
    @typelevel-bot banned @jdegoes
  • Jan 31 2019 21:17
    codecov-io commented #484
  • Jan 31 2019 21:08
    scala-steward opened #484
  • Jan 31 2019 18:19
    andywhite37 commented #189
  • Jan 31 2019 02:41
    kamilongus starred typelevel/cats-effect
  • Jan 30 2019 00:01
    codecov-io commented #483
  • Jan 29 2019 23:51
    deniszjukow opened #483
  • Jan 29 2019 23:37
  • Jan 29 2019 23:22
  • Jan 29 2019 20:26
    Rui-L starred typelevel/cats-effect
  • Jan 29 2019 18:01
    jdegoes commented #480
  • Jan 29 2019 17:04
    thomaav starred typelevel/cats-effect
  • Jan 28 2019 17:43
    asachdeva starred typelevel/cats-effect
  • Jan 28 2019 07:12
    alexandru commented #480
  • Jan 28 2019 05:45
    codecov-io commented #482
  • Jan 28 2019 05:35
    daron666 opened #482
  • Jan 27 2019 13:56
    codecov-io commented #481
  • Jan 27 2019 13:46
    lrodero opened #481
  • Jan 27 2019 05:47
    codecov-io commented #460
  • Jan 27 2019 05:37
    codecov-io commented #460
Adam Rosien
@arosien
:O
Fabio Labella
@SystemFw
yeah I think this channel is going to be for user questions (which I think is a good thing)
Aleksander Sumowski
@aleksandersumowski
hi all,
what would be a good way to extend IO.race to more then 2 tasks?
Fabio Labella
@SystemFw
@aleksandersumowski do they all return the same thing?
things of the same type I mean
Aleksander Sumowski
@aleksandersumowski
yes
This message was deleted
Fabio Labella
@SystemFw
@aleksandersumowski this should work
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
Aleksander Sumowski
@aleksandersumowski
thanks a lot!
Daniel Ochoa Rodríguez
@tzimisce012
About this PR: typelevel/cats-effect#365 Does it miss ConcurrentEffectfor IorT or am I missing something?
Vasil Vasilev
@vasilmkd
surprise, it was traverse
Daniel Ochoa Rodríguez
@tzimisce012
?
Anton Sviridov
@keynmol
just a running gag about .traverse being the answer to pretty much any cats-effect question online :)
Paul Snively
@paul-snively
It's really interesting how often questions reduce to "How do I turn a Traverse of A into a B[Traverse] given an A => F[B]? And enough Fs form Applicatives that the answer really is traverse.
Anton Sviridov
@keynmol
I actually wonder if Future.sequence pops up with same frequency. May be it's because it's part of a smaller public Future interface that it's discovered more easily
Daniel Ochoa Rodríguez
@tzimisce012
oh, it was related with the previous question, I was out of context
Vasil Vasilev
@vasilmkd
ah, sorry for the confusion :)
Fabio Labella
@SystemFw
tbh, there is enough going on in that code that "just use traverse" doesn't feel fair :)
Vasil Vasilev
@vasilmkd
completely agree
Adam Rosien
@arosien
i was going to approach the multi-race as a fold using race, but i liked @SystemFw's solution
Gabriel Volpe
@gvolpe
Adam Rosien
@arosien
cool
i'm saving things like these for advanced exercises
Fabio Labella
@SystemFw
probably a good idea to add an attempt after complete, although it doesn't affect correctness
James Rockett
@jrockett6
Does IO always have to "bubble up" through your code?
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 of IO[F] or a monad transformer or something (when say previously they just returned an Option or something)
If that makes sense..
sinanspd
@sinanspd

and now all calling functions must return some form of IO[F]

Is F another effect here or were you just referring to some arbitrary wrapped type?

James Rockett
@jrockett6
Just some arbitrary wrapped type, sorry I'm still getting used to notation
sinanspd
@sinanspd
Ok just want to make sure :)
James Rockett
@jrockett6
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?
Daniel Spiewak
@djspiewak

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 of IO[F] or a monad transformer or something (when say previously they just returned an Option 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

sinanspd
@sinanspd

and now all calling functions must return some form of IO[F]

Do you have a specific reason to be against this?. It doesn't have to bubble up but it is highly recommended that you run it at the end of the world. Obvious power of IO is the easy composibility and how the underlying IOs can be run without much hassle (I recommend watching @SystemFw 's amazing talk on Fibers). If you run the IO within the nested function, it is not gonna be much different than awaiting and you throw away the concurrency and all the advantages cats give you.

Daniel Spiewak
@djspiewak

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 of IO[F] or a monad transformer or something (when say previously they just returned an Option or something)

Also I realized upon re-reading the rest of your messages that you were probably asking a different question than what I answered. :-)

Yes, IO always "bubbles up" in your program. The only way to eliminate an IO[A] (and get an A) is to use unsafeRunSync() or similar, but as the name implies, this is very... unsafe. :-) The reason this is unsafe is two-fold. First, if the function which returns an IO[A] uses any sort of asynchronous machinery (which you can't know without inspecting it!), then unsafeRunSync() will block a thread unnecessarily. This is anathema to any sort of scale or throughput and will lead to thread starvation, or in the worst case, deadlocks.

The second reason is a bit trickier, but it boils down to what we often refer to as "referential transparency". If I have an expression that looks like foo(somethingComplex, somethingComplex), I might want to take somethingComplex and put it into a val a = somethingComplex, so that I can do foo(a, a). When I do this, I'm exploiting referential transparency. It literally just means "you can safely factor out duplication without changing your program".

Except you can't do this if somethingComplex involves an unsafe function. You can do it if it involves IO, but not if it involves unsafe. So you lose some ability to refactor and reason about your program whenever you use unsafe things.

This is why IO does "bubble out", as you observed, and that's a good thing. :-)

James Rockett
@jrockett6
Ok that makes a lot of sense, thanks for the responses! @sinanspd I will definitely check out that talk, thanks
I might post my issue here just for confirmation, and maybe you could suggest what might be idiotmatic given the situation :D I post it a couple days ago.. but I'm working with:
  private def checkValidPair(argsPair: List[String]): Either[String, Unit] = argsPair.head match {
    case "--f" => checkFileExists[IO](argsPair.tail.head).ifM("This is where things went wrong :)")
  }

  private def checkFileExists[F[_]: Sync](file: String): F[Boolean] =
    Sync[F].delay(Files.exists(Paths.get(file)))


  private def parseArgs(args: List[String]): Either[String, Unit] =
    for {
      _ <- checkArgsEmpty(args)
      pair <- args.sliding(2).toList
      _ <- checkIfPair(pair)
      _ <- checkValidFlag(pair.head)
      _ <- checkValidPair(pair)

    }
James Rockett
@jrockett6
I'm guessing a possible solution would be to split up the for comprehension into the first 4 functions that are pure and just return an Either[String, Unit]. And then the side effecting function checkValidPair could be called separately. Or I could change every function to return a EitherT[IO, String, Unit] or something like that - but that's what I was trying to avoid hence the bubble up question
oh and parseArgs is the entry point btw
sinanspd
@sinanspd
has anyone recommend decline to you yet?
James Rockett
@jrockett6
No
Oh shoot, I was recommended Validated but I totally forgot to look into that
sinanspd
@sinanspd

https://github.com/bkirwi/decline

It's pure functional command line parsing

James Rockett
@jrockett6
Cool!
sinanspd
@sinanspd
might help you by eliminating the worry about the side effects that come with the command line
James Rockett
@jrockett6
Yeah haha I guess that's a problem that's been solved a million times already
Thanks!
David Flynn
@WickedUk_gitlab
I have a long running task I want to run in the background suspended in IO. It has its own shutdown mechanism and I don't care about the return result. What's the right way to start it?
Main task is also an IO and runs with unsafeRunSync
James Rockett
@jrockett6
I'm new to cats, so I may not be very helpful. But have you taken a look at Bracket or Resource?
https://typelevel.org/cats-effect/typeclasses/bracket.html
https://typelevel.org/cats-effect/datatypes/resource.html