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

Return Failure early in <* and *> too #190

Merged
merged 1 commit into from
Oct 29, 2019

Conversation

josephcsible
Copy link
Contributor

Checklist:

HLint

  • I've changed the exposed interface (add new reexports, remove reexports, rename reexported things, etc.).
    • I've updated hlint.dhall accordingly to my changes (add new rules for the new imports, remove old ones, when they are outdated, etc.).
    • I've generated the new .hlint.yaml file (see this instructions).

General

  • I've updated the CHANGELOG with the short description of my latest changes.
  • All new and existing tests pass.
  • I keep the code style used in the files I've changed (see style-guide for more details).
  • I've used the stylish-haskell file.
  • My change requires the documentation updates.
    • I've updated the documentation accordingly.
  • I've added the [ci skip] text to the docs-only related commit's name.

Copy link
Contributor

@chshersh chshersh left a comment

Choose a reason for hiding this comment

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

Thanks for your contribution! However, I propose an alternative solution to this problem.

Short-circuiting behaviour of these operators can be tested manually via some unit tests later.

src/Relude/Extra/Validation.hs Show resolved Hide resolved
@josephcsible
Copy link
Contributor Author

I also added a unit test to ensure the short-circuiting works correctly, for all of the Applicative methods.

Copy link
Contributor

@chshersh chshersh left a comment

Choose a reason for hiding this comment

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

Thanks! I feel like documentation for the Validation module can be improved. But I have plans on how to do this and will do it separately 👍

Copy link
Member

@vrom911 vrom911 left a comment

Choose a reason for hiding this comment

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

Sorry, I'm slow, but I don't see the point of these changes 🤔 Could you please explain what benefits this PR gives the library?

@josephcsible
Copy link
Contributor Author

Consider this code:

case thisWillFail *> thisWillTakeALongTime of
  Failure _ -> print "It didn't work."
  Success _ -> print "It worked!"

Since we know that the whole expression will be a Failure after the LHS fails, we now emit Failure itself sooner, so that thisWillTakeALongTime doesn't need to be evaluated unless/until the argument to Failure is evaluated.

Copy link
Contributor

@chshersh chshersh left a comment

Choose a reason for hiding this comment

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

After thinking more about this PR and discussing it with @vrom911, I now believe that removing code and potentially breaking working code is not a good idea. In general, it's preferable to avoid changing the code in such a considerable way without confidence. And the current example in the documentation is also not helpful. So let's not merge this PR until we have better testing and documentation story for Validation.

@vrom911
Copy link
Member

vrom911 commented Sep 21, 2019

Sure, I do understand that, but I'm talking exactly about this PR. This feels like unchecked breaking change. @chshersh are you sure you would like to take such a risk? I'm personally using Validation in production, so I wouldn't hurry to get to the newer version of relude then.

@josephcsible
Copy link
Contributor Author

Am I missing something? How is this a breaking change?

@chshersh
Copy link
Contributor

@vrom911 Agree with you here. I'm also using Validation in production and it works. We have a separate issue to implement tests for Validation. So let's not change the code yet if it's untested.

@josephcsible
Copy link
Contributor Author

Actually, this is worse than just a performance problem; we're not a valid Applicative:

The other methods have the following default definitions, which may be overridden with equivalent specialized implementations:

  • u *> v = (id <$ u) <*> v
  • u <* v = liftA2 const u v

(emphasis mine) Ours aren't equivalent. If u = Failure ["foo"] and v = undefined, then the LHS of both of those evaluate to undefined, but the RHS of both evaluate to Failure undefined.

@josephcsible
Copy link
Contributor Author

Now that #176 is fixed, is this ready to merge?

@chshersh
Copy link
Contributor

@josephcsible Well, since we have tests now, we actually can implement our own more optimised versions of these operators (like it how was done at first). Because now we have more guarantees that they will work. And we won't rely on the inliner too much as a pleasant consequence.

@josephcsible
Copy link
Contributor Author

@chshersh Done.

Copy link
Contributor

@chshersh chshersh left a comment

Choose a reason for hiding this comment

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

@josephcsible Thanks for the refactoring, looks good 👍

Copy link
Member

@vrom911 vrom911 left a comment

Choose a reason for hiding this comment

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

Thanks, @josephcsible !

@@ -143,6 +145,9 @@ Success 8

>>> liftA2 (+) a c
Failure ["Not correct"]

>>> [x | Success x <- [ha <*> e, c <* e, d *> e, liftA2 (+) d e]]
Copy link
Member

Choose a reason for hiding this comment

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

Heh, I wish these variable names could make a little sense, so the examples could become useful 😢
@chshersh should I create an issue for refactoring this?

Copy link
Contributor

Choose a reason for hiding this comment

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

@vrom911 Yes, please!

Copy link
Member

Choose a reason for hiding this comment

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

@chshersh chshersh merged commit 6a1c2ee into kowainik:master Oct 29, 2019
@josephcsible josephcsible deleted the failearly branch October 29, 2019 12:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants