Search code examples
haskellgenericsrecordtype-inferenceeither

Typeable for Maybe and Either


I would like to test if all fields in a record have the same specified constructor. ext1Q works for Maybe type but not Either type. Why is that?

{-# LANGUAGE DeriveDataTypeable #-}
import Data.Maybe (isNothing, isJust)
import Data.Either (isLeft, isRight)
import Data.Data (Data, gmapQ)
import Data.Generics.Aliases (ext1Q)

allNothing :: (Data d) => d -> Bool
allNothing = and . gmapQ (const True `ext1Q` isNothing)

allJust :: (Data d) => d -> Bool
allJust = and . gmapQ (const True `ext1Q` isJust)

allLeft :: (Data d) => d -> Bool
allLeft = and . gmapQ (const True `ext1Q` isLeft)
CheckIfAllFieldsAreNothing.hs:18:35: error:
    • Could not deduce (base-4.16.3.0:Data.Typeable.Internal.Typeable
                          a0)
        arising from a use of ‘ext1Q’
      from the context: Data d
        bound by the type signature for:
                   allLeft :: forall d. Data d => d -> Bool
        at CheckIfAllFieldsAreNothing.hs:17:1-32
      or from: Data d1
        bound by a type expected by the context:
                   forall d1. Data d1 => d1 -> Bool
        at CheckIfAllFieldsAreNothing.hs:18:23-49
      The type variable ‘a0’ is ambiguous
    • In the first argument of ‘gmapQ’, namely
        ‘(const True `ext1Q` isLeft)’
      In the second argument of ‘(.)’, namely
        ‘gmapQ (const True `ext1Q` isLeft)’
      In the expression: and . gmapQ (const True `ext1Q` isLeft)
   |
18 | allLeft = and . gmapQ (const True `ext1Q` isLeft)

Attempts: There is no "Type Class" application, so I can't "assign" a Typeable (Either a b) constraint.


Solution

  • Of course,

    ext1Q :: (Data d, Typeable t) => (d -> q) -> (forall e. Data e => t e -> q) -> d -> q
    ext2Q :: (Data d, Typeable t) => (d -> q) -> (forall d1 d2. (Data d1, Data d2) => t d1 d2 -> q) -> d -> q
    

    (forall e. Data e => t e -> q) is suitable for isNothing / isJust while (forall d1 d2. (Data d1, Data d2) => t d1 d2 -> q) is suitable for isLeft / isRight.

    I just need to choose the right type extension of queries for different type constructors.