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

Add Semigroup and Monoid instances for GenT that lift the inner Monoid #156

Merged
merged 2 commits into from
Mar 10, 2018

Conversation

andrewthad
Copy link
Contributor

This uses the technique suggested in Equational Reasoning at Scale to provide a Monoid instance for GenT. This was motivated by more than just theoretical concerns. At work, I was recently in a situation where I needed to flatten a list of generators like this:

flatten :: [Gen ByteString] -> Gen ByteString

With the instances provided by this PR, flatten is just mconcat. I've written these instances so that they should be compatible with all phases Semigroup-Monoid-Proposal that are represented by GHC 8.4 and lower.

@andrewthad
Copy link
Contributor Author

cc @chessai

@chessai
Copy link
Contributor

chessai commented Feb 10, 2018

I needed this at work the other day, in the situation @andrewthad described.

Also, thanks for doing this, @andrewthad. I meant to do so when I got over the flu.

@andrewthad
Copy link
Contributor Author

No problem. I figured that when you're running a giant fever, there are probably more pressing things on your mind.

@@ -522,6 +524,16 @@ instance (MonadGen m, Monoid w) => MonadGen (Strict.RWST r w s m) where
------------------------------------------------------------------------
-- GenT instances

-- technically, the Monoid constraint on @a@ could be weakened
Copy link
Member

Choose a reason for hiding this comment

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

Nitpick: technically should start with an upper-case T, so it looks sane in Haddock docs on Hackage.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This comment does not currently show up in haddock docs, but I can make it show up there since that might actually be mildly useful information for users of the library.

Copy link
Member

Choose a reason for hiding this comment

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

Can just leave this unannotated after adopting George's feedback

-- technically, the Monoid constraint on @a@ could be weakened
-- to Semigroup, but this would be annoying for older GHCs
-- where Semigroup is not a superclass of Monoid.
instance (Monad m, Monoid a) => Semigroup (GenT m a) where
Copy link
Contributor

Choose a reason for hiding this comment

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

I would prefer that you weaken the constraint to Semigroup a and delete the comment.

this would be annoying for older GHCs

Not if the user depends on the semigroups package, as I've written about. It provides Semigroup compatibility at least as far back as GHC 7.2.

On the flip-side, the current approach would be unhelpful to any user whose type is a Semigroup but not a Monoid.

I have made this change on my fork here if you'd like to use that patch.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, George's version looks right to me

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good call. I had originally thought this wouldn't work with pre-SMP base, but it totally does. This is certainly the best option. I merged it into the PR.

@thumphries
Copy link
Member

Thanks for the PR!

This seems like the most sensible monoid for GenT. Anyone object?

@andrewthad
Copy link
Contributor Author

I've merged @gwils changes into the PR.

@gwils
Copy link
Contributor

gwils commented Feb 12, 2018

I've just had a look at the definition of GenT and I'm wondering if we want to give Tree a similar liftA2-ish Semigroup and Monoid instance. Then on GenT we could GeneralizedNewtypeDeriving our way to Semigroup and Monoid.

I'm not sure whether that's a reasonable thing to have on Tree though. Is there a more suitable Monoid for it?

Don't let this concern hold up the PR, but I thought I'd mention it.

@andrewthad
Copy link
Contributor Author

I'm not sure whether that's a reasonable thing to have on Tree though. Is there a more suitable Monoid for it?

I would argue that this is always the most appropriate Monoid instance for any Applicative type. Various discussion around this topic:

But yeah, I agree that it would be better to discuss that on a separate PR.

@thumphries
Copy link
Member

I'm not sure whether that's a reasonable thing to have on Tree though.

Tree is internal, so unless there's an internal motivation it's not important either way. This change looks fine as is.

I would argue that this is always the most appropriate Monoid instance for any Applicative type.

Agree, the Alternative-based instance doesn't seem too compelling.

Will wait for @jystic to weigh in before merging, but LGTM.

Thanks for the contribution! Hope you're getting value out of Hedgehog.

@andrewthad
Copy link
Contributor Author

Does @jystic have any additional thoughts on this?

@thumphries thumphries merged commit 31c588f into hedgehogqa:master Mar 10, 2018
@thumphries
Copy link
Member

thumphries commented Mar 10, 2018

Thanks again for the PR!

@chessai
Copy link
Contributor

chessai commented Mar 10, 2018

@thumphries thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants