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

Add sequenceEitherT #113

Merged
merged 2 commits into from
Jan 13, 2017
Merged

Add sequenceEitherT #113

merged 2 commits into from
Jan 13, 2017

Conversation

thumphries
Copy link
Contributor

These are combinators for running a batch of Either expressions independently, folding the error messages together if any of them fail.

I have been pasting foldEither around the place quite a bit lately, and recently needed foldEitherT, so I thought they might be general enough to propose here.

You can generalise to Semigroup but that would require reimplementing Errors, which is a handy validation type we get for free from transformers.

! @jystic @erikd-ambiata

@erikd-ambiata
Copy link
Contributor

I'm ok with this. I can see that being useful. Hell I've even worked around this issue (twice) in Blowfish by returning an Either a b list, splitting it with partitionEithers and then testing that I have an empty list on the left.

However, since it is going into one of our base libraries, I'd like to get some more eyes on it.

@markhibberd
Copy link
Contributor

I am good with code and implementation, but would rather naming reflect sequence then fold, I would expect foldEither = either.

@@ -204,3 +211,28 @@ joinErrorsEither =
tryEitherT :: (Functor m, MonadCatch m, Exception e) => (e -> x) -> m a -> EitherT x m a
tryEitherT handler = firstEitherT handler . newEitherT . try
{-# INLINE tryEitherT #-}

-- | Lift an 'Either' into 'Errors'.
hoistErrors :: Either e a -> Errors e a
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name doesn't really match the naming / usage of the other two hoist functions:

hoistEither :: Monad m => Either x a -> EitherT x m a
hoistMaybe :: Monad m => x -> Maybe a -> EitherT x m a

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not exported (maybe it should be?), but i'll rename it

Copy link
Contributor

@jacobstanley jacobstanley Jan 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given:

Control.Applicative.Lift.runErrors :: Errors e a -> Either e a

Maybe mkErrors ?


-- | Like 'sequence', but folding/accumulating all errors in case of a 'Left'.
foldEither :: (Monoid e, Traversable f) => f (Either e a) -> Either e (f a)
foldEither =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type of this is similar to sequence:

sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)

Would prefer something like:

sequenceEither :: (Traversable t, Monoid x) => t (Either x a) -> Either x (t a)

(Also x for the Left type variable to be consistent with the rest of the module)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or perhaps mconcatEither, not sure, but fold I would expect to take an argument

Copy link
Contributor Author

@thumphries thumphries Jan 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been calling it sequenceErrors in my code, but proposed fold as it's essentially a (monoidal) fold of the left. Names are hard.

@thumphries
Copy link
Contributor Author

Anyone mind sequenceEither and sequenceEitherT?

@charleso
Copy link
Contributor

sequenceEither sounds good to me 👍


-- | Lift an 'Either' into 'Errors'.
eitherErrors :: Either e a -> Errors e a
eitherErrors e =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, good with this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Export y/n?

Honestly the Errors type is only mildly useful because it's limited to applicative. It's also a type synonym, so I prefer not to use it directly.

If you happen to want to use it, you'd probably want this function, else you have to learn how Lift works.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

n

I'd be happy to not export it, as your other functions don't mention Errors at all

{-# INLINE eitherErrors #-}

-- | Like 'sequence', but folding/accumulating all errors in case of a 'Left'.
sequenceEither :: (Monoid x, Traversable f) => f (Either x a) -> Either x (f a)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/f/t/

@thumphries thumphries changed the title Add foldEitherT Add sequenceEitherT Jan 13, 2017
@jacobstanley
Copy link
Contributor

📻

@thumphries thumphries merged commit 96d8137 into master Jan 13, 2017
@thumphries thumphries deleted the topic/foldEitherT branch January 13, 2017 04:36
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.

5 participants