Control operators have two kinds of arguments: function arguments (which are arrows) and arrow arguments. For an example, consider a function like local:
local :: ArrowReader r arr => arr e a -> arr (e, r) a
Like local from MonadReader, this runs the argument in a modified environment (though unlike the MonadReader version, it accepts the environment directly instead of being given a function to apply to it). Using it in arrow notation looks like this:
y <- (| local (f -< x) |) r
This works okay when the argument to local is small, but it becomes very confusing when the argument command is large. For example, I might want to run a whole block with a modified environment, so I would have to write something like this:
r <- ask -< ()
w <- (| local (do
y <- f -< x
z <- g -< y
h -< (y, z))
|) (foo $ bar r)
I think this looks totally backwards. Very often, when writing monadic code, I do something like this:
w <- flip local (foo . bar) $ do
y <- f x
z <- g y
h y z
But there isn’t any way to write code that way in arrow notation. This means that if I have a series of nested control operators, I end up with something like
(| withRecordInconsistency
((| withRecordDependencies
((| mapErrorA (f -< (e, s))
|) \e -> "in permission for role " <> roleName <<> ": " <> e)
|) metadataObject schemaObject)
|) metadataObject
which looks terrible and is hard to read. The equivalent monadic code it was adapted from looks like
withRecordInconsistency metadataObject $
withRecordDependencies metadataObject schemaObject $
modifyErr (\e -> "in permission for role " <> rn <<> ": " <> e) $
m
Control operators have two kinds of arguments: function arguments (which are arrows) and arrow arguments. For an example, consider a function like
local
:Like
local
fromMonadReader
, this runs the argument in a modified environment (though unlike theMonadReader
version, it accepts the environment directly instead of being given a function to apply to it). Using it in arrow notation looks like this:This works okay when the argument to
local
is small, but it becomes very confusing when the argument command is large. For example, I might want to run a whole block with a modified environment, so I would have to write something like this:I think this looks totally backwards. Very often, when writing monadic code, I do something like this:
But there isn’t any way to write code that way in arrow notation. This means that if I have a series of nested control operators, I end up with something like
which looks terrible and is hard to read. The equivalent monadic code it was adapted from looks like
which is far better.