Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional mapping functions #182

Open
andrewthad opened this issue Sep 27, 2016 · 6 comments
Open

Additional mapping functions #182

andrewthad opened this issue Sep 27, 2016 · 6 comments

Comments

@andrewthad
Copy link

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
@andrewthad
Copy link
Author

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

@andrewthad
Copy link
Author

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
Copy link
Owner

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
Copy link
Author

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
Copy link
Author

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

@treeowl
Copy link
Collaborator

treeowl commented Dec 11, 2019

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants