
Hello Everyone, I am trying to do homework #3 of Stephanie Weirich's programming class. It is about QuickCheck. http://www.seas.upenn.edu/~cis552/current/hw/hw03/index.html However, quickCheck is magically coming up with the wrong answer! I am loading a very simple file (distilled from the homework). Here it is: ~~~~ import Test.QuickCheck ------------------------------------------------------------------------------ prop_const :: Eq a => (a -> a -> a) -> a -> a -> Bool prop_const const' a b = const' a b == a const_bug :: a -> b -> b const_bug _ b = b -- Oops: this returns the *second* argument, not the first. --main = quickCheck (prop_const const) ~~~~ Now, I just wanted to check that 'prop_const' holds for the 'const' function, but fails for 'const_bug' So, I fired up GHCi, but here's what happens: econ1gw-131-21-dhcp:week3 dimitri$ ghci GHCi, version 7.6.3: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. Prelude> :l weird-quickcheck.hs [1 of 1] Compiling Main ( weird-quickcheck.hs, interpreted ) weird-quickcheck.hs:22:1: Warning: The import of `Test.QuickCheck' is redundant except perhaps to import instances from `Test.QuickCheck' To import instances alone, use: import Test.QuickCheck() Ok, modules loaded: Main. *Main> const 1 2 1 *Main> const_bug 1 2 Loading package array-0.4.0.1 ... linking ... done. Loading package deepseq-1.3.0.1 ... linking ... done. Loading package old-locale-1.0.0.5 ... linking ... done. Loading package time-1.4.0.1 ... linking ... done. Loading package random-1.0.1.1 ... linking ... done. Loading package primitive-0.5.0.1 ... linking ... done. Loading package pretty-1.1.1.0 ... linking ... done. Loading package containers-0.5.0.0 ... linking ... done. Loading package template-haskell ... linking ... done. Loading package tf-random-0.5 ... linking ... done. Loading package transformers-0.3.0.0 ... linking ... done. Loading package QuickCheck-2.7.6 ... linking ... done. 2 *Main> :t prop_const prop_const :: Eq a => (a -> a -> a) -> a -> a -> Bool *Main> quickCheck (prop_const const) +++ OK, passed 100 tests. *Main> quickCheck (prop_const const_bug) +++ OK, passed 100 tests. *Main> quickCheck (prop_const const_bug :: Char -> Char -> Bool) *** Failed! Falsifiable (after 1 test and 2 shrinks): 'a' 'b' *Main> This makes no sense to me! First, I have no idea how quickCheck is able to run any tests at all as the type of 'const' is: *Main> :t const const :: a -> b -> a In other words, it's a polymorphic type. Second, why does GHCi load so many files when I try to evaluate 'const_bug'? Finally and most puzzling, why does quickCheck give out the wrong result if I don't specify the type when testing 'const_bug'? That's really scary. It means that quickCheck can easily fool me if I forget to specify the necessary types. (GHC complains if I uncommented the '--main' line, so I can only do this in GHCi.) I am totally lost here, any pointers would be much appreciated. Thanks, Dimitri

On Fri, Oct 17, 2014 at 10:55 AM, Dimitri DeFigueiredo < defigueiredo@ucdavis.edu> wrote:
Finally and most puzzling, why does quickCheck give out the wrong result if I don't specify the type when testing 'const_bug'?
Quickcheck properties must be monomorphic. Otherwise defaulting rules set you up for () and hilarity ensues. Did you google "quickcheck polymorphic types"? -- Kim-Ee

Thanks Kim-Ee! This makes more sense now. It does still seem like very unsafe default behavior by quickCheck. In other words, quickcheck shouldn't be designed to let code pass all tests if its user (me) forgets to make a property monomorphic. In any case, the following two links suggested by your google search were very useful: http://www.haskell.org/pipermail/haskell/2009-October/021657.html and the related paper http://www.cse.chalmers.se/~bernardy/PolyTest.pdf Thanks again, Dimitri On 16/10/14 22:34, Kim-Ee Yeoh wrote:
On Fri, Oct 17, 2014 at 10:55 AM, Dimitri DeFigueiredo
mailto:defigueiredo@ucdavis.edu> wrote: Finally and most puzzling, why does quickCheck give out the wrong result if I don't specify the type when testing 'const_bug'?
Quickcheck properties must be monomorphic. Otherwise defaulting rules set you up for () and hilarity ensues.
Did you google "quickcheck polymorphic types"?
-- Kim-Ee
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

On Fri, Oct 17, 2014 at 1:53 AM, Dimitri DeFigueiredo < defigueiredo@ucdavis.edu> wrote:
This makes more sense now. It does still seem like very unsafe default behavior by quickCheck.
QuickCheck has no way of knowing that ghci has ExtendedDefaultRules enabled, and (quite aside from the difficulty of doing type-case in Haskell) I'm not sure that arbitrarily declaring types involving () to be user error is a good idea. -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

I agree we have to pick a poison here and I didn't know that the Extended Default Rules were the culprit, but I think the end result is scary because forgetting a type signature is about the most common mistake I make. Having that imply that tests will silently pass means (to me) that it's not safe to use Quickcheck with GHCi. Or, just remember to always make properties monomorphic. "Always!" I would be much more comfortable using quickCheck' the version where () implies user error, as you suggested. For me that is an enhacement to quickCheck that allows it to be used in GHCi, but that is just my opinion. In any case, thanks for shedding more light on the reasons behind the design. Dimitri On 17/10/14 07:59, Brandon Allbery wrote:
On Fri, Oct 17, 2014 at 1:53 AM, Dimitri DeFigueiredo
mailto:defigueiredo@ucdavis.edu> wrote: This makes more sense now. It does still seem like very unsafe default behavior by quickCheck.
QuickCheck has no way of knowing that ghci has ExtendedDefaultRules enabled, and (quite aside from the difficulty of doing type-case in Haskell) I'm not sure that arbitrarily declaring types involving () to be user error is a good idea.
-- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com mailto:allbery.b@gmail.com ballbery@sinenomine.net mailto:ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

On Fri, Oct 17, 2014 at 2:55 PM, Dimitri DeFigueiredo < defigueiredo@ucdavis.edu> wrote:
I agree we have to pick a poison here and I didn't know that the Extended Default Rules were the culprit, but I think the end result is scary because forgetting a type signature is about the most common mistake I make. Having that imply that tests will silently pass means (to me) that it's not safe to use Quickcheck with GHCi. Or, just remember to always make properties monomorphic. "Always!"
It might make more sense to have a warning in the QuickCheck documentation that, from ghci, it's best to ":seti -XNoExtendedDefaultRules" (and/or add that to .ghci / ghci.ini) to avoid surprises. -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

That is a great idea! I'm changing my ghci configuration as I write this. Problem solved! Thanks, Dimitri On 17/10/14 13:16, Brandon Allbery wrote:
On Fri, Oct 17, 2014 at 2:55 PM, Dimitri DeFigueiredo
mailto:defigueiredo@ucdavis.edu> wrote: I agree we have to pick a poison here and I didn't know that the Extended Default Rules were the culprit, but I think the end result is scary because forgetting a type signature is about the most common mistake I make. Having that imply that tests will silently pass means (to me) that it's not safe to use Quickcheck with GHCi. Or, just remember to always make properties monomorphic. "Always!"
It might make more sense to have a warning in the QuickCheck documentation that, from ghci, it's best to ":seti -XNoExtendedDefaultRules" (and/or add that to .ghci / ghci.ini) to avoid surprises.
-- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com mailto:allbery.b@gmail.com ballbery@sinenomine.net mailto:ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
participants (3)
-
Brandon Allbery
-
Dimitri DeFigueiredo
-
Kim-Ee Yeoh