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(): A
Bob Glamm
01/30/2020, 7:27 PMIO<E, A>
whereas cats-effect has IO[A]
(and E
is implicitly fixed to Throwable
)IO<E, A>.attempt: IO<E, Either<Throwable, A>>
enables translation of Throwable
into a custom error hierarchy E
Hiosdra
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... 🤷)