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

Correct the Applicative & MonadFix instances for ErrorC #228

Merged
merged 7 commits into from
Sep 29, 2019
Merged

Conversation

robrix
Copy link
Contributor

@robrix robrix commented Sep 28, 2019

It was previously incorrect in that throwError e <*> a would diverge when a diverged, but ap (throwError e) a would not.

It was previously incorrect in that `throwError e <*> a` would diverge when `a` diverged, but `throwError e \`ap\` a` would not.
@robrix robrix changed the title Correct the Applicative instance for ErrorC. Correct the Applicative instance for ErrorC Sep 28, 2019
@robrix robrix marked this pull request as ready for review September 28, 2019 22:06
Copy link
Contributor Author

@robrix robrix left a comment

Choose a reason for hiding this comment

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

Ready for review.

newtype ErrorC e m a = ErrorC { runErrorC :: m (Either e a) }
deriving (Functor)
newtype ErrorC e m a = ErrorC { runErrorC :: ExceptT e m a }
deriving (Applicative, Functor, Monad, Fail.MonadFail, MonadFix, MonadIO, MonadTrans)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Defining ErrorC atop ExceptT simultaneously fixes the unlawful Applicative instance and allows us to remove a great number of hand-written instances.

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 also fixes the divergent MonadFix instance.


instance Alternative m => Alternative (ErrorC e m) where
empty = ErrorC empty
instance (Alternative m, Monad m) => Alternative (ErrorC e m) where
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We still define our own Alternative and MonadPlus instances in order to retain our existing semantics instead of adopting ExceptT’s (which handles them itself using a Monoid constraint on e instead of passing them along to m).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we leave this as documentation in the file? Haddocks on those instances, maybe?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good call 👍

@robrix robrix changed the title Correct the Applicative instance for ErrorC Correct the Applicative & MonadFix instances for ErrorC Sep 28, 2019
Copy link
Collaborator

@patrickt patrickt left a comment

Choose a reason for hiding this comment

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

Brilliant. One small thing, but this is ready to go once it’s fixed.

@robrix robrix merged commit 8cb9c2f into master Sep 29, 2019
@robrix robrix deleted the lawful-errorc branch September 29, 2019 14:24
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.

ErrorC’s mfix diverges ErrorC’s Applicative instance is unlawful
2 participants