Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to derive instances for records with type-families

Here's what I'm trying but it doesn't compile:

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE FlexibleInstances #-}

import Data.Text as T
import Data.Int (Int64)

type family Incoming validationResult baseType
type instance Incoming Validated baseType = baseType
type instance Incoming ValidationErrors baseType = Either [T.Text] baseType

data Validated
data ValidationErrors

data Tag = Tag {unTag :: T.Text} deriving (Eq, Show)

data NewTag f = NewTag
  {
    ntClientId :: Incoming f Int64
  , ntTag :: Incoming f Tag
  }

deriving instance (Show baseType) => Show (Incoming Validated baseType)
deriving instance (Show baseType) => Show (Incoming ValidationErrors baseType)

Compilation errors:

23  38 error           error:
 • Illegal type synonym family application in instance:
     Incoming Validated baseType
 • In the stand-alone deriving instance for
     ‘(Show baseType) => Show (Incoming Validated baseType)’ (intero)
24  38 error           error:
 • Illegal type synonym family application in instance:
     Incoming ValidationErrors baseType
 • In the stand-alone deriving instance for
     ‘(Show baseType) => Show (Incoming ValidationErrors baseType)’ (intero)
like image 690
Saurabh Nanda Avatar asked Feb 05 '23 09:02

Saurabh Nanda


1 Answers

You have two problems here. The first one is what GHC is telling you. Basically, you can't have an instance that depends on a type family (the type family can be there, but only if all the arguments it gets are concrete types). All sorts of bad things can start happening once you allow this, not the least of which is that the right hand side of your type family could have calls to other type families.

Generally, one can solve this sort of problem by moving the type family application to a constraint:

deriving instance (Show baseType, i ~ Incoming Validated baseType) => Show i
deriving instance (Show baseType, i ~ Incoming ValidationErrors baseType) => Show i

Doing this actually makes the second problem obvious: your instance heads are too general.

That said, I'm not sure there is even anything to fix - just get rid of the deriving lines. You would like the first one to boil down to saying: derive an instance of Show basetype given the Show basetype constraint (which is completely pointless). The second one is equally pointless - Either already has an instance of Show.

like image 106
Alec Avatar answered Feb 16 '23 02:02

Alec