6

How do I use the checkers library to test the Functor laws of a simple Parser?

import Test.QuickCheck
import Test.QuickCheck.Checkers
import Test.QuickCheck.Classes
import qualified Data.ByteString as BS

type Index = Int

newtype Parser a = Parser (BS.ByteString -> Index -> (a, Index))

runParser :: Parser a -> BS.ByteString -> Index -> (a, Index)
runParser (Parser p) = p

instance Functor Parser where
    f `fmap` p = Parser $  \bs i -> 
      let (a, ix) = runParser p bs i
      in (f a, ix)

I think I have to use the functor function from Test.QuickCheck.Classes

The type is:

functor :: forall m a b c. (Functor m, Arbitrary a, Arbitrary b, Arbitrary c, 
           CoArbitrary a, CoArbitrary b, Show (m a), Arbitrary (m a), EqProp (m a), EqProp (m c)) 
           => m (a, b, c) -> TestBatch

Now m should probably be my Functor Parser, so I need something like

main :: IO ()
main = = quickBatch (functor (Parser (a, b, c))

But what do I use for (a, b, c) ?

Note: I know a quick QuickTest test is not a proof and I have read the discussion in How do I test this applicative instance with checkers? (No instance for CoArbitrary (Validation e0 [Char])) . However if the quick test fails, I know that my Functor instance is broken...

Edit

I made a little progress: I can write

main :: IO ()
main = quickBatch $ functor (undefined :: Parser (Int, String, Char))

This gives an error: No instance for (Show (Parser Int))

In the type signature of functor, there is no Read instance mentioned, so I can write

instance Show (Parser a) where
   show (Parser a) = "Parsers cannot be printed"

This the gives a new error:

• No instance for (Arbitrary (Parser Int))
    arising from a use of ‘functor’
• In the second argument of ‘($)’, namely

and I guess this is a tougher problem...

Jogger
  • 1,617
  • 2
  • 12
  • 22
  • free theorem says you will just need to check identity law. is that possible for you to generate parser instance and see if identity law holds? i don't really know checkers, though. – Jason Hu Nov 19 '17 at 20:05
  • The implementation of `functor` ensures that the *values* of `a`, `b`, and `c` are irrelevant; only their *types* matter (perhaps it should take a proxy argument instead, but this is likely more convenient in most cases). But I'm not sure how you're supposed to choose those types. – dfeuer Nov 19 '17 at 20:09

0 Answers0