Hey, nice! You might want to add a Readme that clarifies the order in which to read the files. I thought Layer 4 was the last file to read, not the first one.
I would love to know how you jam Except
-ion handling into this mix too
ReaderT env monad output
is isomorphic to env -> monad output
, which is read as “if you give me an environment value, I will give you (but not yet run) a monadic computation that produces an output
value.” You then run that computation via launchAff
/runAff
.
If you want to change that sentence to, “If you give me an environment value, I will give you a monadic computation that produces either a successful output (i.e. Right output
) or an error (i.e. Left error
),” then you would want a type signature like env -> monad (Either error output)
.
When we translate complex monads to monad transformers, we start with the inside part first. monad (Either error output)
is synonymous with ExceptT error monad output
. If we update our function type signature to use this new “monadic type,” we get env -> ExceptT error monad output
. We now want to replace the env ->
part with ReaderT
, so we get ReaderT env (ExceptT error monad) output
.
Now that we have ExceptT
in our stack, we can use MonadCatch
and MonadError
throughout our code base.
However, the ExceptT
transformer constrains us to use only one error type throughout the entire code base. If we want to use Variant
instead, we can use checked-exceptions, which exists for this very purpose.
I believe someone packaged up a library that defines the below type, but I can’t recall where and what the library was called:
-- isomorphic to:
-- env -> monad (Either (Variant errorRows) monad output
newtype REvT env errorRows monad output =
ReaderT env (ExceptV errorRows monad) output