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

implement runPartial. Run monadic actions and extract a return value if ... #135

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

alang9
Copy link

@alang9 alang9 commented Feb 9, 2015

...possible

Seems to be a useful utility function that's currently missing.

@Gabriella439
Copy link
Owner

Can you give an example of how you planned to use this?

@alang9
Copy link
Author

alang9 commented Feb 10, 2015

My particular application is something like this:

consumerToIteratee :: (Monad m, I.Nullable a) => Consumer a m r -> I.Iteratee a m r
consumerToIteratee = go
  where
    go consumer = do
      a <- I.getChunk
      out <- lift $ runPartial $ return a >~ consumer
      case out of
        Left r -> return r
        Right next -> go next

where I.Iteratee is from the iteratee package.

@Gabriella439
Copy link
Owner

In this case you can use runEffect instead of runPartial. return a >~ consumerwill type-check as an Effect, meaning that it's guaranteed not to have any Request/Respond constructors.

You can also tell that it won't have any Request/Respond constructors by observing that Consumer only has Request/Pure/M constructors, and then (return a >~) eliminates all the Request constructors.

@alang9
Copy link
Author

alang9 commented Feb 10, 2015

I see. I think >~ doesn't do what I thought it did. Upon further inspection, I agree that runPartial is not very useful, but I would like a function like feed

feed :: Monad m => a -> Consumer a m r -> m (Either r (Consumer a m r))
feed a = go
  where
    go c = case c of
      Request () fu -> go2 (fu a)
      Respond v _ -> closed v
      M m -> m >>= go
      Pure r -> return (Left r)
    go2 c = case c of
      Request _ _ -> return (Right c)
      Respond v _ -> closed v
      M m -> m >>= go2
      Pure r -> return (Left r)

To be able to write:

consumerToIteratee :: (Monad m, I.Nullable a) => Consumer a m r -> I.Iteratee a m r
consumerToIteratee = go
  where
    go consumer = do
      a <- I.getChunk
      out <- lift $ feed a consumer
      case out of
        Left r -> return r
        Right next -> go next

Alternately, feed could be the following, in which case it looks dual to next:

feed2 :: Monad m => a -> Consumer a m r -> m (Either r (a -> Consumer a m r))
feed2 a = go
  where
    go c = case c of
      Request () fu -> go2 (fu a)
      Respond v _ -> closed v
      M m -> m >>= go
      Pure r -> return (Left r)
    go2 c = case c of
      Request () fu -> return (Right fu)
      Respond v _ -> closed v
      M m -> m >>= go2
      Pure r -> return (Left r)

@Gabriella439
Copy link
Owner

I like the idea of some feed-like function that lets you step Consumer. Could I suggest this slight variation on the type signature you gave

feed :: Monad m => Consumer a m r -> m (Either r (a -> Consumer a m r))

Notice how you don't supply the a directly to feed. Instead, it may give you a (a -> Consumer a m r) and you supply the a to that instead.

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

Successfully merging this pull request may close these issues.

2 participants