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
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
Raas Ahsan
@RaasAhsan
Concurrent.background is the recommended way to start an IO concurrently and "ignore" its outcome
which does return a Resource :)
David Flynn
@WickedUk_gitlab
Is there any documentation for this?
looks like Gitter doesn't recognize the whole link, but the Scaladoc is the most comprehensive description we have of the method I believe
David Flynn
@WickedUk_gitlab
Okay thanks, there should be a rule, no documentation on the webpage, the feature doesn't exist :-)
Otherwise you're getting misdirected by the documentation that is there to do it another way.
Raas Ahsan
@RaasAhsan
Yeah, I'm with you all the way there. The majority of the documentation on the website was written before 1.x was released, and new features and changes since then are more or less neglected by it
one of which was Concurrent.background IIRC
David Flynn
@WickedUk_gitlab
I'd be happy to help out, but I'm still pretty much an effect newbie. With a certain other tech doing all it can to establish itself, if that becomes easier to get up to speed with, then cats effect will begin to decline, which would be a shame given the work gone into it.
val longProcess = (IO.sleep(5.seconds) *> IO(println("Ping!"))).foreverM

val srv: Resource[IO, ServerBinding[IO]] = for {
  _ <- longProcess.background
  server <- server.run
} yield server

val application = srv.use(binding => IO(println("Bound to " + binding)) *> IO.never)
What's server.run ?
Raas Ahsan
@RaasAhsan
That would be very much appreciated! We've identified gaps in documentation as an issue and have been taking some steps to address it. For the next CE release, there will actually be a completely new documentation site (content will remain unchanged for now). Most of the current maintainer efforts are dedicated towards CE3 though, where we're aiming to be much stricter on documentation standards
So, in that example, Resource is being used to scope the lifecycle of some dummy application that starts a longProcess and some kind of network server, both of which are captured via Resource
David Flynn
@WickedUk_gitlab
so server.run is something else that also runs, but we don't care what it is or how it does it, just that longProcess.background doesn't block the flow ?
Raas Ahsan
@RaasAhsan
yeah, exactly. as long as you're inside the scope of that nested Resource, longProcess will continue to run (unless it terminates on its own)
David Flynn
@WickedUk_gitlab
And I suspect if it was a complete example it would be pinging the server
Raas Ahsan
@RaasAhsan
Yeah, we should honestly have complete examples for things like this.