3

I am trying to implement my own functor instances and quickcheck them, and have run into issues on typeclasses which are not instances of Eq, namely (->) and IO. My attempts result in a No instance for (Eq ...) error.

In the (->) case I had run into a similar error with Show, i.e. No instance for (Show ...), and was able to fix that by adding a Show (a -> b) instance as suggested in an answer here. It would seem that I might be able to solve also the lack of Eq instances by adding them similarly. However, this question on function equality notes that that in Haskell creating an instance of Eq (a -> b) is equivalent to the halting problem and therefore impossible.

I'm not sure whether creating an instance of Eq IO a is possible. In the IO case I also run into a No instance for (Arbitrary ...) error.

Is there some way to quickcheck the functor properties of the function type (->)? Is there some way to do the same for the IO type?

My code is as follows.

import Prelude hiding (Functor, fmap)
import Test.QuickCheck
import Test.QuickCheck.Function

class Functor f where
  fmap :: (a -> b) -> f a -> f b

instance Functor IO where
  fmap h f = f >>= (pure . h)

instance Functor ((->) e) where
  fmap = (.)

data T a = T

prop_functorid :: (Functor f, Eq (f a)) => T (f a) -> f a -> Bool
prop_functorid T x = fmap id x == x

prop_functorcompose :: (Functor f, Eq (f c)) => T (f a) -> T b -> T c -> f a -> Fun a b -> Fun b c -> Bool
prop_functorcompose T T T x (apply -> g) (apply -> h) =
  fmap (h . g) x == (fmap h . fmap g) x

instance Show (a -> b) where
  show a= "function"

prop_function :: IO ()
prop_function = do
  quickCheck $ prop_functorid (T :: T (String -> String))
  quickCheck $ prop_functorcompose (T :: T (String -> String)) (T :: T String) (T :: T String)

prop_io :: IO ()
prop_io = do
  quickCheck $ prop_functorid (T :: T (IO String))
  quickCheck $ prop_functorcompose (T :: T (IO String)) (T :: T String) (T :: T String)

main = do
  prop_function
  prop_io
mherzl
  • 5,624
  • 6
  • 34
  • 75
  • There is an arbitrary instance for functions `(CoArbitrary a, Arbitrary b) => Arbitrary (a -> b)` you can then test for equality for functions - if you evaluate pointwise - i.e. you generate arbitrary `a` and compare the `f a` values – epsilonhalbe May 22 '17 at 14:19
  • for IO - you need to write your own Arbitrary instance - and except for the trivial instance `arbitrary = fmap pure . arbitrary` I cannot think of a reasonable one. – epsilonhalbe May 22 '17 at 14:21
  • Usually, functions for QuickCheck should be represented by its `Fun` type. – dfeuer May 22 '17 at 15:38
  • You might want to use the `(.&&.)` operator from `Test.QuickCheck.Property` to combine properties, instead of creating an IO action and checking individually each property every time. – baxbaxwalanuksiwe May 22 '17 at 18:26
  • 1
    There is absolutely no way to verify the functor instance for `IO`, because your function (properly) requires `Eq (f a)` but you cannot have an instance `Eq (IO A)` for any type `A`. Functions are another story - a bit difficult, but [doable](https://hackage.haskell.org/package/QuickCheck-2.9.2/docs/Test-QuickCheck-Function.html). – user2407038 May 23 '17 at 05:20

0 Answers0