"read: no parse" with functionShow

Brent Yorgey byorgey at seas.upenn.edu
Sun Jul 22 15:01:48 BST 2012


On Sun, Jul 22, 2012 at 02:01:49PM +0100, Nick Smallbone wrote:
> Hi Brent,
> 
> You're right that functionShow internally generates a partial function
> on Strings - I hadn't thought much about that before. In itself, this
> isn't a problem: the function won't be applied to arbitrary strings,
> only to strings in the image of show, and QuickCheck should shrink
> away the partially-defined parts to leave a total function which can
> be printed. Indeed, you can generate a random function this way and
> try applying it to an Elt and see that it works.
> 
> The problem is that Test.QuickCheck.Function's shrinking doesn't work
> on partial functions. The shrink function will return _|_ instead of a
> list of shrink candidates. Also, if you apply a showable function at
> an input where there's no matching case, we pick a default result;
> this default result is taken from the image of the function so can be
> _|_ if the function is partial. I've just pushed a patch that fixes
> all this: the shrinking works for partial functions, and we generate
> default results using arbitrary instead.

Hi Nick,

Thanks for the response.  It works *more often* for me now (though it
seems to run two-three times slower).  But I still sometimes get a
"read: no parse" error.  Here is an excerpt from some output:

  process/keepDelimsL match               *** Failed! Falsifiable (after 22 tests and 3 shrinks):    
  Exception thrown by generator: 'Prelude.read: no parse'
  NonEmpty {getNonEmpty = [Elt {unElt = 'c'},Elt {unElt = 'c'},Elt {unElt = 'b'},Elt {unElt = 'a'},Elt {unElt = 'a'},Elt {unElt = 'd'}]}

(Note that I expect a test failure; I deliberately introduced a bug.)
The property in question takes two arguments, Splitter Elt and
NonEmptyList Elt.  A Splitter Elt has several fields, one of which is
a Delimiter Elt, which is defined by

  newtype Delimiter a = Delimiter [a -> Bool]

and has an Arbitrary instance given by

  instance (Arbitrary a, CoArbitrary a, Function a) => Arbitrary (Delimiter a) where
    arbitrary = (Delimiter . map apply) <$> arbitrary

i.e. it generates an arbitrary list [Fun Elt Bool] using the Function
Elt instance, then converts it to an actual [Elt -> Bool] list.
Should this work?  Am I doing something wrong here?  I'm happy to send
you more info/a link to the repo if it would help.

-Brent



More information about the QuickCheck mailing list