Search code examples
haskellquickcheck

Haskell: create Function instance


I'm currently learning Haskell from the ever awesome Haskell from first principles, and while trying to check the functor instances for each datatype using QuickCheck, I've stumbled against a mayor problem creating a Function instance for my Four datatype:

data Four' a b = Four' a a a b deriving (Eq,Show)
instance Function (Four' a b) where
  function =  let
                  injection :: (Function a, Function b) => (Four' a b) -> (a,a,a,b)
                  injection (Four' x1 x2 x3 z1) = (x1,x2,x3,z1)
                  surjection :: (Function a, Function b) => (a,a,a,b) -> (Four' a b)
                  surjection (x1,x2,x3,z1) = (Four' x1 x2 x3 z1)
              in functionMap injection surjection

which throws the following error:

Error: • No instance for (Function a) arising from a use of ‘functionMap’
  Possible fix:
    add (Function a) to the context of
      the type signature for:
        function :: forall b1. (Four' a b -> b1) -> Four' a b :-> b1
      or the instance declaration
• In the expression: functionMap injection surjection

Also, what is exactly the difference between trying to create a Function instance and an Arbitrary instance if they both generate functions?


Solution

  • I have some doubts that's really what you want. Some explanation of what you are trying to do which requires Function would help us tell whether that's the case.

    But to answer the technical question that's already there, Function (and CoArbitrary, which you will also need if you actually need Function) have default, generic implementations, so you don't need to do or understand any of it.

    1. Derive Generic
    2. Write empty instances of Function and CoArbitrary
    {-# LANGUAGE DeriveGeneric #-}
    
    import GHC.Generics (Generic)
    import Test.QuickCheck
    
    data Four a b = ... deriving (Eq, Show, Generic)  -- Derive generic
    
    -- Default implementations
    instance (Function a, Function b) => Function (Four a b)
    instance (CoArbitrary a, CoArbitrary b) => CoArbitrary (Four a b)
    

    Also,what is exactly the difference between trying to create a Function instance and an arbitrary instance if they both generate functions?

    • Arbitrary a: "how to generate and shrink values of type a"
    • CoArbitrary a+Function a: "how to generate and shrink values of type a -> b (for suitably constrained b)"

    These are not the same.