haskellderived-instances

How to create StandaloneDeriving instances


Given the following code

{-# LANGUAGE StandaloneDeriving  #-}

type Date = Int
data Decision a = Decision a deriving (Show)  

data InProgress a = InProgress {progress :: a, decision :: Decision a } deriving (Show)
data Finished a = Finished {finished :: a, initial :: a, timestamp :: Date } deriving (Show)  

data LineItem a = LineItem {article :: a String, amount :: a Float, units :: a Int } deriving (Show)  

I get the following error

source_file.hs:11:96:
    No instance for (Show (a Float))
    arising from the second field of ‘LineItem’ (type ‘a Float’)
    Possible fix:
    use a standalone 'deriving instance' declaration,
        so you can specify the instance context yourself
    When deriving the instance for (Show (LineItem a))

I tried some variations like this below - but I cant get it run.

deriving instance Show a => Show (InProgress Float)

How can I fix this? (and some explanation would be really appreciated)

Edit

Okay, I have the solution

deriving instance Show (LineItem InProgress)

will do what I want. Still I dont get why its not

deriving instance Show a => Show (LineItem (InProgress a))

Solution

  • The a is LineItem a is not a type, i.e. it has not kind *. Instead, it has kind * -> *.

    This means that a is expected to be replaced with a type constructor. For instance, LineItem Maybe is well-kinded, but LineItem (Maybe Int) is not.

    The most general Show instance is then something like

    deriving instance (Show (a String), Show (a Int), Show (a Float)) 
                      => Show (LineItem a)
    

    but there the context involves more complex types than the head. This will surely require to turn on UndecidableInstances and possibly a few other extensions.

    Note that, since this instance does not "simplify" the head into smaller constraints, there's the chance that by adding further "bad" instances we can make the compiler to loop forever. In practice, this rarely happens, and I wouldn't worry too much about it.

    If you know a in subsequent uses has only a finite number of cases, you can list them one by one, providing an instance for each one, as you did in your edit.

    deriving instance Show (LineItem TyCon1)
    ...
    deriving instance Show (LineItem TyConN)