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

defined Alternative #33

Merged
merged 2 commits into from
Jan 4, 2024
Merged

Conversation

BebeSparkelSparkel
Copy link
Contributor

No description provided.

@andreasabel
Copy link
Collaborator

Thanks @BebeSparkelSparkel !
Could you please provide proofs of the monad and alternative laws in a comment with the instance declaration?

@BebeSparkelSparkel
Copy link
Contributor Author

Added to tests.

@andreasabel
Copy link
Collaborator

I was a bit surprised to read that there isn't a consensus about what the laws for Alternative should be: https://en.wikibooks.org/wiki/Haskell/Alternative_and_MonadPlus#Other_suggested_laws

I am a bit hesitant here still. Does it make sense to have Alternative for a monad that does destructive updates like ST? In, general, even if a fails and b succeeds, a <|> b will then have also updates coming from a.

@josefs What do you think?

@andreasabel andreasabel requested a review from josefs December 26, 2023 00:38
@BebeSparkelSparkel
Copy link
Contributor Author

@andreasabel Alternative is defined for IO so it is hard to say that monads with destructive updates should not have an Alternative instance.

@andreasabel andreasabel self-assigned this Jan 4, 2024
@andreasabel andreasabel added this to the 0.4.8 milestone Jan 4, 2024
@andreasabel andreasabel merged commit b3afb10 into josefs:master Jan 4, 2024
23 checks passed
@andreasabel
Copy link
Collaborator

Thanks @BebeSparkelSparkel ! Published as 0.4.8.

@josefs
Copy link
Owner

josefs commented Jan 12, 2024

Apologies for the late reply, I've been on an extended sick leave.

I would have liked to see a good motivating example here.

Side effects in STT cannot be "undone" so these kinds of instances are rather dodgy. Now, as far as I understand, the laws of Alternative are not strong enough to require that side effects be undone, unlike MonadPlus. So I'm not going to ask to revert this. But whoever decides to use this better know what they're doing.

Below is the kind of program I'm worried about. The result of this function is 1 but someone unfamiliar with the difference between Alternative and MonadPlus might think it should be 0. So there's a real risk of confusion here.

foo = do
  r <- newSTRef 0
  (modifySTRef (+1) r >> lift empty <|> return ())
  readSTRef r

@andreasabel
Copy link
Collaborator

Apologies for the late reply, I've been on an extended sick leave.

Sorry to hear, and glad that your are back! I wish you a good 2024!

I would have liked to see a good motivating example here.

@BebeSparkelSparkel: Would you provide such an example?

Side effects in STT cannot be "undone" so these kinds of instances are rather dodgy. Now, as far as I understand, the laws of Alternative are not strong enough to require that side effects be undone, unlike MonadPlus. So I'm not going to ask to revert this. But whoever decides to use this better know what they're doing.

Below is the kind of program I'm worried about. The result of this function is 1 but someone unfamiliar with the difference between Alternative and MonadPlus might think it should be 0. So there's a real risk of confusion here.

I am not good a precedences for these operators. I suppose this is the following, right?

foo = do
  r <- newSTRef 0
  ((modifySTRef (+1) r >> lift empty) <|> return ())
  readSTRef r

@BebeSparkelSparkel
Copy link
Contributor Author

This is not a finished example but is where I am using it

 86             (whileM
 87               (do
 88                 addDigit =<< charToDigit =<< index
 89                 inc
 90                 decExponent
 91                 return True
 92               <|> return False))

@josefs
Copy link
Owner

josefs commented Jan 20, 2024

@andreasabel :

I am not good a precedences for these operators. I suppose this is the following, right?

Yes.

@BebeSparkelSparkel can you explain where in the do block the computation can fail and where you update references?

@BebeSparkelSparkel
Copy link
Contributor Author

Both index and charToDigit can fail.

addDigit, inc, and decExponent all mutate.

Runs in the Maybe monad.

@josefs
Copy link
Owner

josefs commented Feb 1, 2024

Thank for the example @BebeSparkelSparkel . That is indeed a valid usecase as there doesn't seem to be any potential failures after mutation.

@BebeSparkelSparkel
Copy link
Contributor Author

@josefs Thanks for checking on this

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