Safe Haskell | None |
---|---|
Language | Haskell2010 |
TL;DR
We go from this:
(| withRecordInconsistency ( (| modifyErrA ( do (info, dependencies) <- liftEitherA -< buildRelInfo relDef recordDependencies -< (metadataObject, schemaObject, dependencies) returnA -< info ) |) (addTableContext @b table . addRelationshipContext) ) |) metadataObject
to this:
withRecordInconsistencyM metadataObject $ do modifyErr (addTableContext @b table . addRelationshipContext) $ do (info, dependencies) <- liftEither $ buildRelInfo relDef recordDependenciesM metadataObject schemaObject dependencies return info
Background
We use Haskell's Arrows
language extension to gain some syntactic sugar when
working with Arrow
s. Arrow
s are a programming abstraction comparable to
Monad
s.
Unfortunately the syntactic sugar provided by this language extension is not very sweet.
This module allows us to sometimes avoid using Arrows
syntax altogether,
without loss of functionality or correctness. It is a demo of a technique that
can be used to cut down the amount of Arrows
-based code in our codebase by
about half.
Approach
Although in general not every Monad
is an Arrow
, specific Arrow
instantiations are exactly as powerful as their Monad
equivalents. Otherwise
they wouldn't be very equivalent, would they?
Just like liftEither
interprets the
monad into an arbitrary
monad implementing Either
e
, we add interpret certain concrete monads
such as MonadError
e
into arrows satisfying
constraints, in this example the ones satisfying Writer
w
. This
means that the part of the code that only uses such interpretable arrow
effects can be written monadically, and then used in arrow constructions
down the line.ArrowWriter
w
This approach cannot be used for arrow effects which do not have a monadic
equivalent. In our codebase, the only instance of this is
, implemented by the
ArrowCache
m
arrow. So code written with
Rule
m
in the context cannot be rewritten
monadically using this technique.ArrowCache
m
Synopsis
- interpretWriter :: ArrowWriter w arr => Writer w a `arr` a
Documentation
interpretWriter :: ArrowWriter w arr => Writer w a `arr` a Source #
Translate a monadic writer effect stack of a computation into arrow-based effects.
NB: This is conceptually different from ArrowKleisli
, which inserts a
single monadic effect into an arrow-based effect stack.
NB: This is conceptually different from ArrowApply
, which expresses that a
given Arrow
is a Kleisli arrow. ArrowInterpret
has no such condition
on arr
.