Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
Oleg Pyzhcov
@oleg-py
You can also have dynamic, structural typing :-D
Gavin Bisesi
@Daenyth
depending on the language, yeah, if you're used to python etc
Oleg Pyzhcov
@oleg-py
Though that is a hellscape to program in for a prolonged period of time
Gavin Bisesi
@Daenyth
or golang I suppose - that would be especially crippling to learning pure FP style abstraction
Oleg Pyzhcov
@oleg-py
Maybe it's just that in FP there's much more containers and data. Like if you squint hard enough, every monad is a container as we know
Gavin Bisesi
@Daenyth
well
I don't agree with that intuition. I can squint hard enough to see it but I think it leads people astray
I think I'm coming to the opinion that the learning curve is very different for some people. If you're a developer who thinks in terms of design and abstraction and systems and CS theory already, you're going to have a much easier time than if you're in the "get it running fast" / run-edit-iterate til it works camp
especially because implicits and scala tooling in general is very hostile to the second style
Oleg Pyzhcov
@oleg-py
Well I actually meant that parametric polymorphism is more widely applicable because you switch from "containers" to "effects"
Gavin Bisesi
@Daenyth
lots of compiler errors / bad type inference / you need to "just know" where a lot of things are / hard to search for what you're trying to find
yeah
Benjamin Nash
@benash
Hi everyone, is there an idiomatic way to "tap" into an element right before it's processed by parTraverse, e.g. for say logging? The best I could come up with is this loggedProcess function, but it doesn't seem very reusable:
  val l = (1 to 12).toList
  def process(i: Int) = IO.delay(i * 2)

  def loggedProcess(i: Int): IO[Int] = for {
    _ <- IO.delay(println(s"Starting $i"))
    res <- process(i)
  } yield res

  override def run(args: List[String]) = {
    val t = for {
      res <- l.parTraverse(el => loggedProcess(el))
      _ <- IO.delay(println(res.size))
    } yield res
    t.unsafeRunSync()
    IO.delay(ExitCode.Success)
  }
Billzabob
@Billzabob
There is a parTraverse for anything with a Traverse instance, which List has. The function you pass into parTraverse has to return something with a Parallel instance, which Either does have (it’s Validated).
Gerry Fletcher
@gerryfletch
@arosien Nice cheatsheet!
Henri Cook
@henricook
I'm sure i just don't know the rule for this, but why does NonEmptySet not implement partition like in the std lib Set? https://github.com/typelevel/cats/blob/master/core/src/main/scala/cats/data/NonEmptySet.scala
Henri Cook
@henricook
is it because the resulting partitions are not guaranteed to be non-empty?
Richard
@Executioner1939
      Ior
        .fromOptions(context.user.flatMap(_.token), response.throwable)
        .bitraverse()
I see there is bitraverse, but it's red, with cats.implicits._ in scope
Oleg Pyzhcov
@oleg-py
@Executioner1939 in Intellij?
Richard
@Executioner1939
Yeah
Oleg Pyzhcov
@oleg-py
Intellij might highlight extension methods as red if parameter count is wrong — and there's no zero parameter bitraverse
Richard
@Executioner1939
      Ior
        .fromOptions(context.user.flatMap(_.token), response.throwable)
        .bitraverse(token => decryptJwt(token), ex => Task.now(ex))
It's highlight this as wrong
Oleg Pyzhcov
@oleg-py
Sorry, I was a bit wrong. Ior.fromOptions returns Option[A Ior B] (None if both were empty), and there's no Bitraverse[Option]
Richard
@Executioner1939
Oh I see, ofcourse, as Ior has to be either Left, Right or Both, can't be None
Not paying attention, I apologise for wasting time :see_no_evil: :see_no_evil:
Adam Rosien
@arosien
@benash you could IO.delay(println(...)) *> process(i), where *> is an alias for productR, or if you want to effect after you could use flatTap
Benjamin Nash
@benash
@arosien Very cool! Thanks for pointing that out.
Philip
@philipschwarz
@zainab-ali thanks
Travis Brown
@travisbrown
Louis Bettens
@lourkeur
@travisbrown I was reading your comments about attemptNarrow.
Why doesn't List("") match {case x: List[Int] => x} raise at least a warning? It does in Scastie
Rob Norris
@tpolecat
Ammonite doesn't warn by default but everything else should give a loud warning.
That shouldn't compile at all, I don't know why it's allowed.
Louis Bettens
@lourkeur
I did in fact use Ammonite
Dotty warns the type test for List[Int] cannot be checked at runtime which is a tiny bit better imho.
Rob Norris
@tpolecat
Put interp.configureCompiler(_.settings.nowarnings.value = false) in your ammonite predef. I don't really understand why it's off by default.
Maybe there's still time to make it an error in Dotty.
Louis Bettens
@lourkeur
Thank you!
Anthony Cerruti
@srnb_gitlab
Resource is technically a monad transformer, right?
Rob Norris
@tpolecat
No it’s a lot more than that.
Luka Jacobowitz
@LukaJCB
It depends on the definition of monad transformer
Rob Norris
@tpolecat
To me a transformer is just a newtype that selects different typeclass instances. It’s isomorphic to the non-transformed value.
But yeah I don’t know if there’s a generally accepted definition. That’s how I think about them because it’s very easy to explain.
Luka Jacobowitz
@LukaJCB
Right, you could make a claim it’s isomorphic to F[(A, (ExitCase[Throwable]) ⇒ F[Unit])] but probably most people don’t think about it that way
If the definition of monad transformer is that for any MT[F, A] if F is a monad than MT[F, *] is also a monad, then technically it isn’t because it needs Bracket in addition to monad
Wikipedia supports that definition: https://en.wikipedia.org/wiki/Monad_transformer
Rob Norris
@tpolecat
:+1:
Anthony Cerruti
@srnb_gitlab
So its not a monad transformer, but it is a monad if F is a bracket?
Luka Jacobowitz
@LukaJCB
yep!