-
Notifications
You must be signed in to change notification settings - Fork 123
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
Added All and Any monoids #397
Conversation
C.f. #279. |
The tricky thing here is deciding if this is the right point on the tradeoff spectrum. Maybe having Monoid Property and Any as an option is another good option? Another problem here is that the names Any and All are taken in base. The build also fails on a bunch of older GHC versions (and Hugs) but thats not a huge deal - it should be pretty easy to address. |
src/Test/QuickCheck.hs
Outdated
@@ -315,8 +315,10 @@ module Test.QuickCheck | |||
, (.&.) | |||
, (.&&.) | |||
, conjoin | |||
, All (..) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These re-exports will for sure cause pain down the line. Without re-exporting from the main module the names are less of an issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. It's better to remove them.
Note that |
src/Test/QuickCheck/Monoids.hs
Outdated
-- Note: monoid laws are satisfied up to `isSuccess` unless one is using | ||
-- `checkCoverage`. | ||
-- | ||
data All = forall p. Testable p => All { getAll :: p } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe AllOf
/ AnyOf
or AllHold
/ AnyHolds
etc.? To unclash with Data.Monoid
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or maybe And
and Or
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
another idea: Every
/ Some
src/Test/QuickCheck/Monoids.hs
Outdated
-- Use `property @Any` as an accessor which doesn't leak | ||
-- existential variables. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand what this means, can you give an example / explanation here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider you have an abient function which returns Property
, if you try to use getAny
GHC will complain that forall p. Testable p => p
is not Property
, or it might error by saying that an existential p
is leaking, in that scenario just using property
(or property . getAny
) is what one needs.
λ a = All True
λ :t a
a :: All
λ :t getAll a
<interactive>:1:1: error: [GHC-55876]
• Cannot use record selector ‘getAll’ as a function due to escaped type variables
• In the expression: getAll a
Suggested fix: Use pattern-matching syntax instead
λ :t case a of All x -> x
<interactive>:1:20: error: [GHC-25897]
• Couldn't match expected type ‘p’ with actual type ‘p1’
‘p1’ is a rigid type variable bound by
a pattern with constructor:
All :: forall p. Testable p => p -> All,
in a case alternative
at <interactive>:1:11-15
‘p’ is a rigid type variable bound by
the inferred type of it :: p
at <interactive>:1:1
• In the expression: x
In a case alternative: All x -> x
In the expression: case a of All x -> x
• Relevant bindings include x :: p1 (bound at <interactive>:1:15)
but
λ :t property a
property a :: Property
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I see what you mean. I'm inclined to say at this point that it's better to just not say anything / point out that the types are Testable
.
Also, the type of getEvery
and getSome
are such that they can basically never be used. I'd prefer to remove them from the code all together to keep it cleaner.
src/Test/QuickCheck/Monoids.hs
Outdated
-- Use `property @All` as an accessor which doesn't leak | ||
-- existential variables. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand what this means, please give an example.
tests/Monoids.hs
Outdated
-- , pure $ Any (checkCoverage $ cover 100 False "" True) | ||
-- , pure $ Any (checkCoverage $ cover 100 False "" False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-- , pure $ Any (checkCoverage $ cover 100 False "" True) | |
-- , pure $ Any (checkCoverage $ cover 100 False "" False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, when I included them, all tests pass - unlike for All / Every
where the unit property fails.
@MaximilianAlgehed I addressed your comments. |
Great! Please fix the build failures and I'll have a look next week! (OOTO this week) |
@MaximilianAlgehed could you approve the workflows to run? |
Something went terribly wrong with all the linux jobs:
|
Let's try to re-run them. |
@coot sorry for the delay but the fix has been merged |
I rebased this PR. |
Ok, sorry... You need to rebase again because I screwed up with the semantics of github actions and the difference between "run on push" and "run on PR". There is no neat way to get "run on push and also run on PR from forks"... Anway, hopefully this works for now. |
Done. |
`All` is a monoid build around `.&&.`. It is useful when writing complex properties which check multiple conditions. Since it is a monoid it allows one to use `foldMap` which is often much more ergonomic than using `conjoin`. `All` satisfies `monoid` laws up to `isSuccess`, unless one is using `checkCoverage` & `cover`. I'd argue this is not a problem since `checkCoverage` and `cover` are most often added at the top of the property. This patch also adds `Any` monoid build around `.||.`. Tests are also included.
Let's see if I fixed |
All
is a monoid build around.&&.
. It is useful when writingcomplex properties which check multiple conditions. Since it is
a monoid it allows one to use
foldMap
which is often much moreergonomic than using
conjoin
.All
satisfiesmonoid
laws up toisSuccess
, unless one is usingcheckCoverage
&cover
. I'd argue this is not a problem sincecheckCoverage
andcover
are most often added at the top of theproperty.
This patch also adds
Any
monoid build around.||.
.Tests are also included.