nick8325/quickcheck

discard is too lazy

brandonchinn178 opened this issue · 4 comments

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)

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)

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?

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