Gabriella439 / pipes

Compositional pipelines
BSD 3-Clause "New" or "Revised" License
487 stars 72 forks source link

Additional mapping functions #182

Open andrewthad opened 7 years ago

andrewthad commented 7 years ago

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:

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

andrewthad commented 7 years ago

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

andrewthad commented 7 years ago

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
Gabriella439 commented 7 years ago

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'.

andrewthad commented 7 years ago

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.

andrewthad commented 7 years ago

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

treeowl commented 4 years ago

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