Skip to content

Passing arguments to control operators is often backwards #4

Open
@lexi-lambda

Description

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

which is far better.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions