haskell-checkers / checkers

Check properties on standard classes and data structures
Other
79 stars 13 forks source link

How to use / Proxy #68

Open alt-romes opened 2 years ago

alt-romes commented 2 years ago

Hello,

I was trying to use but as someone unfamiliar with quick check it’s quite hard to understand how to use this library, so much that I’ve decided to open this issue.

I would love to see some examples of functor and monad

From the source I understand the first argument of those functions is just to correctly infer the type of monad to test m, but I don’t understand the triple (a, b, c) and their constraints (QuickCheck related). How am I supposed to call those functions?

A thought: if the argument is discarded and is only there for matters of inference, why not use Data.Proxy which is what I think to be the preferred way of passing an argument for its type?

sjakobi commented 2 years ago

I suggest you look at some code that uses checkers. You can find some examples here: https://packdeps.haskellers.com/reverse/checkers, e.g. https://github.com/twanvl/multiset/blob/3392f94ee25cac145c4a0270b470ca298e32943d/test/multiset-properties.hs.

From the source I understand the first argument of those functions is just to correctly infer the type of monad to test m, but I don’t understand the triple (a, b, c) and their constraints (QuickCheck related). How am I supposed to call those functions?

I think you can pick about any types for a, b and c as long as they satisfy the constraint. The tests will be more likely to catch a problem if you use types where the [Co]Arbitrary instances produce some reasonably good distribution. E.g. using () may cause some issues to go unnoticed.

A thought: if the argument is discarded and is only there for matters of inference, why not use Data.Proxy which is what I think to be the preferred way of passing an argument for its type?

Proxy would definitely be better. I suspect it's not being used here because much of the library was written before Proxy was well-known.

Note that there are similar packages with more "modern" APIs, e.g. https://hackage.haskell.org/package/quickcheck-classes-0.6.5.0/docs/Test-QuickCheck-Classes.html.

In case you're interested in improving the documentation or changing the API to use Proxy, you're welcome to send a PR BTW.

alt-romes commented 2 years ago

OK, thank you for the pointers, I'll get started.

I might send an example.

I have some new questions: Do you keep this API because of backwards compatibility? Don't you want to also provide a modern API? Is this package still valuable despite its less modern API because of featuring perhaps more laws?

But you say I could update the API to use Proxy?

I would have to know better about this library to do changes like that: for example how would monad look with Proxy?

Proxy m -> Proxy a -> Proxy b -> Proxy c? Proxy (m (a, b, c))?

conal commented 2 years ago

Hasn't Proxy been obsoleted by type application?

alt-romes commented 2 years ago

@conal Yes, mostly except for when using type families but needing the argument type still.

However, for a beginner, seeing monad :: forall m ........ => TestBatch it isn't clear at all how to say what kind of monad it is, while Proxy m -> TestBatch makes much more sense (and is better than making users call monad with an undefined :: Type...

I wouldn't pass a proxy to disambiguate a type, but when the library is about testing types it makes sense that the type is somehow "an argument" of the function

conal commented 2 years ago

when the library is about testing types it makes sense that the type is somehow "an argument" of the function

My 2¢: Type application is (GHC-)Haskell's modern, direct way of saying that the type (including higher-kinded) is an argument. The two older techniques you mention predated our ability to say so directly and so instead tried to fudge type applications with (ignored or vacuous) value applications.

alt-romes commented 2 years ago

@conal You're right. I still think it would depend on who we would be showing the library to (forall m. TestBatch does not look like a function that takes arguments), but good documentation could make sure it would be understood

sjakobi commented 2 years ago

I have some new questions: Do you keep this API because of backwards compatibility? Don't you want to also provide a modern API? Is this package still valuable despite its less modern API because of featuring perhaps more laws?

You might be the first person to point out that the current API is bit weird with it's requirement for an arbitrary value to guide type inference. I'm not aware of any previous discussions about modernizing the API.

Backwards compatibility is a concern of course, but if we agree that a different API would be better, why stick with the old cruft?!

Regarding differences to other libraries: The main reason I went with checkers for the multiset-properties is https://github.com/andrewthad/quickcheck-classes/issues/74.

I agree with @conal though, that it would be better to use TypeApplications than Proxy these days.