Gabriella439 / pipes

Compositional pipelines

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Additional mapping functions

andrewthad opened this issue · comments

I just needed this function for something I was doing:

contramapUpstream :: Monad m => (c -> a) -> Pipes.Proxy a' a b' b m r -> Pipes.Proxy a' c b' b m r
contramapUpstream f = go where
  go (Pipes.Request a' g) = Pipes.Request a' (go . g . f)
  go (Pipes.Respond b g) = Pipes.Respond b (go . g)
  go (Pipes.M m) = Pipes.M (m >>= return . go)
  go (Pipes.Pure r) = Pipes.Pure r

I think that this, along with its three sibling functions, would be a good addition to Pipes.Core. The names I envisioned for the functions were:

  • contramapUpstream
  • mapUpstream
  • contramapDownstream
  • mapDownstream

It is possible to be more descriptive, although I find these names needlessly wordy:

  • contramapUpstreamInput
  • mapUpstreamOutput
  • contramapDownstreamInput
  • mapDownstreamOutput

I would be happy to PR this it's considered a good addition to the library.

Also useful are the monadic variants:

contramapUpstreamM :: Monad m => (c -> m a) -> Pipes.Proxy a' a b' b m r -> Pipes.Proxy a' c b' b m r
contramapUpstreamM f = go where
  go (Pipes.Request a' g) = Pipes.Request a' (Pipes.M . (return . go . g <=< f))
  go (Pipes.Respond b g) = Pipes.Respond b (go . g)
  go (Pipes.M m) = Pipes.M (m >>= return . go)
  go (Pipes.Pure r) = Pipes.Pure r

The reason I don't have these is that they can already be done pretty succinctly using the existing utilities in Pipes.Core. For example:

contramapUpstream f p = (fmap f . request) >\\ p
contramapUpstreamM f p = (lift . f <=< request) >\\ p

... although I find it more readable to write them as:

contramapUpstream f p = request' >\\ p
  where
    request' a' = do
        a <- request a'
        return (f a)

contramapUpstreamM f p = request' >\\ p
  where
    request' a' = do
        a <- request a'
        lift (f a)

... since that more clearly conveys that you're replacing all the old requests with a new request'.

Thanks. That's helpful. I've been trying to improve my intuition for building Proxy functions using the Pipes.Core stuff instead of directly pattern matching.

I have a related question, but I decided to ask it on stackoverflow instead.

FWIW, I think these should be added anyway. I don't have an opinion about the names.