Hiosdra
01/30/2020, 7:01 PMtoIO() (mentioned today in #arrow), I saw that attempt is like:
fun attempt(): IO<E, Either<Throwable, A>>
While in Scala Cats there is:
val x: IO[Either[Int, String]] = IO[Either[Int, String]] { Left(1) }
val y: IO[Either[Throwable, Either[Int, String]]] = x.attempt
def attempt: IO[Either[Throwable, A]]
Won’t be more intuitive to type it like this?
Also in actual form I am unable to call IO.attempt().unsafeRunSync() , because unsafeRunSync is like:
fun <A> IOOf<Nothing, A>.unsafeRunSync(): ABob Glamm
01/30/2020, 7:27 PMIO<E, A> whereas cats-effect has IO[A] (and E is implicitly fixed to Throwable)Bob Glamm
01/30/2020, 7:28 PMIO<E, A>.attempt: IO<E, Either<Throwable, A>> enables translation of Throwable into a custom error hierarchy EBob Glamm
01/30/2020, 7:28 PMBob Glamm
01/30/2020, 7:29 PMHiosdra
01/30/2020, 9:53 PMIO[Either[E, A]] is nearly (nested mapping) the same as arrow 0.11.0 IO<E, A> .
Before BIO implementation allowed .attempt().unsafeRunSync() chain, but BIO does not, And I wish why attempt result goes to right value of IO, but not to error side.
Wouldn’t it be less confusing to IO<E, A>.attemt(): IO<Throwable, Either<E, A>> ?Bob Glamm
01/30/2020, 11:25 PMIO<E, A> -> IO<Throwable, Either<E, A>> breaks some monad laws, but I'm not enough of a category theorist to say for sureJannis
01/31/2020, 12:29 AMMonadError instances, one for Throwable and one for E and both have valid use cases! The instance for Throwable is especially important when catching unhandled errors which will eventually appear. The instance for E is perfect for handling domain errors and expected error cases...
So anyway: I like the idea of going IO<E, A>.attempt(): IO<Throwable, Either<E, A>> it neatly makes the unexpected/unhandled error visible, but it still requires multiple steps to get to the Throwable. (But since that is probably expected anyway... 🤷)