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

discard is too lazy #363

Open
brandonchinn178 opened this issue Dec 9, 2023 · 4 comments · May be fixed by #374
Open

discard is too lazy #363

brandonchinn178 opened this issue Dec 9, 2023 · 4 comments · May be fixed by #374

Comments

@brandonchinn178
Copy link

I expect using discard in Gen to discard the current case, but it doesn't discard unless I force it:

-- unexpectedly generates values
sample (discard >>= \_ -> arbitrary :: Gen Int)

-- correctly errors
sample (discard >>= \() -> arbitrary :: Gen Int)
@phadej
Copy link
Contributor

phadej commented Dec 9, 2023

You probably want to use suchThat or its variant if you are in Gen, i.e. writing generators.

EDIT: A simple example trying to discard everything with suchThat will loop, but I doubt that's the real use case.

(It's not discard which is lazy, it's Gen monad - and it must be to allow generating infinite structures)

@brandonchinn178
Copy link
Author

In my specific case, it's a complicated Gen where suchThat wouldnt be easily usable.

Would it be possible to create a version of discard that works even in a lazy Gen monad?

@phadej
Copy link
Contributor

phadej commented Dec 9, 2023

Would it be possible to create a version of discard that works even in a lazy Gen monad?

Not without changing the definition of Gen, as far as I'm aware.

In my specific case, it's a complicated Gen where suchThat wouldnt be easily usable.

Depends on what you mean by "easily", i.e. below is IMO not too complicated (such definition were proposed in literature, not sure if anyone made a library for it though):

You can work with MaybeT Gen, then discard will be return Nothing, lifting ordinary Gen into MaybeT Gen will be lift, and evaluating the MaybeT Gen to Gen would use suchThatMap.

>>> :t \mg -> suchThatMap (runMaybeT mg) id
\mg -> suchThatMap (runMaybeT mg) id :: MaybeT Gen b -> Gen b

@MaximilianAlgehed
Copy link
Collaborator

This is the intended behaviour of Gen as the lazyness allows you to be a bit more fast and loose. One option to make working with discard slightly more ergonomic would be to introduce suchThatDiscard g p = g >>= \ a -> unless (p a) discard >> pure a

@MaximilianAlgehed MaximilianAlgehed linked a pull request Mar 21, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants