    {-# Language CPP, DeriveDataTypeable, DeriveGeneric, DeriveLift, PatternSynonyms, ViewPatterns #-}

    #if MIN_VERSION_template_haskell(2,12,0)
    {-# Language Safe #-}
    #else
    {-# Language Trustworthy #-}
    #endif

    {-|
    Module      : Language.Haskell.TH.Datatype.TyVarBndr
    Description : Backwards-compatible type variable binders
    Copyright   : Eric Mertens 2020
    License     : ISC
    Maintainer  : emertens@gmail.com

    This module provides a backwards-compatible API for constructing and
    manipulating 'TyVarBndr's across multiple versions of the @template-haskell@
    package.

    -}
    module Language.Haskell.TH.Datatype.TyVarBndr (
        -- * @TyVarBndr@-related types
        TyVarBndr_
      , TyVarBndrUnit
      , TyVarBndrSpec
      , TyVarBndrVis
      , Specificity(..)
    #if __GLASGOW_HASKELL__ >= 907
      , BndrVis(..)
    #else
      , BndrVis
      , pattern BndrReq
      , pattern BndrInvis
    #endif
      , DefaultBndrFlag(..)

        -- * Constructing @TyVarBndr@s
        -- ** @flag@-polymorphic
      , plainTVFlag
      , kindedTVFlag
        -- ** @TyVarBndrUnit@
      , plainTV
      , kindedTV
        -- ** @TyVarBndrSpec@
      , plainTVInferred
      , plainTVSpecified
      , kindedTVInferred
      , kindedTVSpecified
        -- ** @TyVarBndrVis@
      , plainTVReq
      , plainTVInvis
      , kindedTVReq
      , kindedTVInvis

        -- * Constructing @Specificity@
      , inferredSpec
      , specifiedSpec

        -- * Constructing @BndrVis@
      , bndrReq
      , bndrInvis

        -- * Modifying @TyVarBndr@s
      , elimTV
      , elimTVFlag
      , mapTV
      , mapTVName
      , mapTVFlag
      , mapTVKind
      , traverseTV
      , traverseTVName
      , traverseTVFlag
      , traverseTVKind
      , mapMTV
      , mapMTVName
      , mapMTVFlag
      , mapMTVKind
      , changeTVFlags

        -- * Properties of @TyVarBndr@s
      , tvName
      , tvKind
      , tvFlag
      ) where

    import Control.Applicative
    import Control.Monad
    import Data.Data (Data)
    import GHC.Generics (Generic)
    import Language.Haskell.TH.Lib
    import Language.Haskell.TH.Syntax

    -- | A type synonym for 'TyVarBndr'. This is the recommended way to refer to
    -- 'TyVarBndr's if you wish to achieve backwards compatibility with older
    -- versions of @template-haskell@, where 'TyVarBndr' lacked a @flag@ type
    -- parameter (if it has one).
    #if MIN_VERSION_template_haskell(2,17,0)
    type TyVarBndr_ flag = TyVarBndr flag
    #else
    type TyVarBndr_ flag = TyVarBndr

    -- | A 'TyVarBndr' without a flag. This is used for 'TyVarBndr's that do not
    -- interact with visible type application and are not binders for type-level
    -- declarations.
    type TyVarBndrUnit = TyVarBndr

    -- | A 'TyVarBndr' with a 'Specificity' flag. This is used for 'TyVarBndr's that
    -- interact with visible type application.
    type TyVarBndrSpec = TyVarBndr

    -- | Determines how a 'TyVarBndr' interacts with visible type application.
    data Specificity
      = SpecifiedSpec -- ^ @a@. Eligible for visible type application.
      | InferredSpec  -- ^ @{a}@. Not eligible for visible type application.
      deriving (Show, Eq, Ord, Data, Generic, Lift)

    inferredSpec :: Specificity
    inferredSpec = InferredSpec

    specifiedSpec :: Specificity
    specifiedSpec = SpecifiedSpec
    #endif

    #if !MIN_VERSION_template_haskell(2,21,0)
    -- | A 'TyVarBndr' with a 'BndrVis' flag. This is used for 'TyVarBndr's in
    -- type-level declarations (e.g., the binders in @data D \@k (a :: k)@).
    type TyVarBndrVis = TyVarBndr_ BndrVis

    -- | Because pre-9.8 GHCs do not support invisible binders in type-level
    -- declarations, we simply make 'BndrVis' an alias for @()@ as a compatibility
    -- shim for old GHCs. This matches how type-level 'TyVarBndr's were flagged
    -- prior to GHC 9.8.
    type BndrVis = ()
    #if __GLASGOW_HASKELL__ >= 802
    {-# COMPLETE BndrReq, BndrInvis #-}
    #endif

    -- | Because pre-9.8 GHCs do not support invisible binders in type-level
    -- declarations, we simply make 'BndrReq' a pattern synonym for @()@ as a
    -- compatibility shim for old GHCs. This matches how type-level 'TyVarBndr's
    -- were flagged prior to GHC 9.8.
    pattern BndrReq :: BndrVis
    pattern BndrReq = ()

    -- | Because pre-9.8 GHCs do not support invisible binders in type-level
    -- declarations, this compatibility shim is defined in a somewhat unusual way:
    --
    -- * As a pattern, 'BndrInvis' will never match on pre-9.8 GHCs. That way, if
    --   you write pattern matches like this:
    --
    --   @
    --   case flag of
    --     'BndrInvis' -> ...
    --     'BndrVis' -> ...
    --   @
    --
    --   Then the first branch will never be taken on pre-9.8 GHCs.
    --
    -- * 'BndrInvis' is a unidirectional pattern synonym on pre-9.8 GHCs, so it
    --   cannot be used as an expression on these GHC versions. This is done in an
    --   effort to avoid pitfalls that could occur if 'BndrInvis' were defined like
    --   so:
    --
    --   @
    --   pattern 'BndrInvis' = ()
    --   @
    --
    --   If this were the definition, then a user could write code involving
    --   'BndrInvis' that would construct an invisible type-level binder on GHC 9.8
    --   or later, but a /visible/ type-level binder on older GHCs! This would be
    --   disastrous, so we prevent the user from doing such a thing.
    pattern BndrInvis :: BndrVis
    pattern BndrInvis <- ((\() -> True) -> False)

    bndrReq :: BndrVis
    bndrReq = ()

    bndrInvis :: BndrVis
    bndrInvis = ()

    -- | A class characterizing reasonable default values for various 'TyVarBndr'
    -- @flag@ types.
    class DefaultBndrFlag flag where
      defaultBndrFlag :: flag

    instance DefaultBndrFlag () where
      defaultBndrFlag = ()

    instance DefaultBndrFlag Specificity where
      defaultBndrFlag = SpecifiedSpec
    #endif

    -- | Construct a 'PlainTV' with the given @flag@.
    plainTVFlag :: Name -> flag -> TyVarBndr_ flag
    #if MIN_VERSION_template_haskell(2,17,0)
    plainTVFlag :: forall flag. Name -> flag -> TyVarBndr_ flag
    plainTVFlag = Name -> flag -> TyVarBndr flag
    forall flag. Name -> flag -> TyVarBndr_ flag
    PlainTV
    #else
    plainTVFlag n _ = PlainTV n
    #endif

    -- | Construct a 'PlainTV' with an 'InferredSpec'.
    plainTVInferred :: Name -> TyVarBndrSpec
    plainTVInferred :: Name -> TyVarBndrSpec
    plainTVInferred Name
    n = Name -> Specificity -> TyVarBndrSpec
    forall flag. Name -> flag -> TyVarBndr_ flag
    plainTVFlag Name
    n Specificity
    InferredSpec

    -- | Construct a 'PlainTV' with a 'SpecifiedSpec'.
    plainTVSpecified :: Name -> TyVarBndrSpec
    plainTVSpecified :: Name -> TyVarBndrSpec
    plainTVSpecified Name
    n = Name -> Specificity -> TyVarBndrSpec
    forall flag. Name -> flag -> TyVarBndr_ flag
    plainTVFlag Name
    n Specificity
    SpecifiedSpec

    -- | Construct a 'PlainTV' with a 'BndrReq'.
    plainTVReq :: Name -> TyVarBndrVis
    plainTVReq :: Name -> TyVarBndrVis
    plainTVReq Name
    n = Name -> BndrVis -> TyVarBndrVis
    forall flag. Name -> flag -> TyVarBndr_ flag
    plainTVFlag Name
    n BndrVis
    bndrReq

    -- | Construct a 'PlainTV' with a 'BndrInvis'.
    plainTVInvis :: Name -> TyVarBndrVis
    plainTVInvis :: Name -> TyVarBndrVis
    plainTVInvis Name
    n = Name -> BndrVis -> TyVarBndrVis
    forall flag. Name -> flag -> TyVarBndr_ flag
    plainTVFlag Name
    n BndrVis
    bndrInvis

    -- | Construct a 'KindedTV' with the given @flag@.
    kindedTVFlag :: Name -> flag -> Kind -> TyVarBndr_ flag
    #if MIN_VERSION_template_haskell(2,17,0)
    kindedTVFlag :: forall flag. Name -> flag -> Kind -> TyVarBndr_ flag
    kindedTVFlag = Name -> flag -> Kind -> TyVarBndr flag
    forall flag. Name -> flag -> Kind -> TyVarBndr_ flag
    KindedTV
    #else
    kindedTVFlag n _ kind = KindedTV n kind
    #endif

    -- | Construct a 'KindedTV' with an 'InferredSpec'.
    kindedTVInferred :: Name -> Kind -> TyVarBndrSpec
    kindedTVInferred :: Name -> Kind -> TyVarBndrSpec
    kindedTVInferred Name
    n Kind
    k = Name -> Specificity -> Kind -> TyVarBndrSpec
    forall flag. Name -> flag -> Kind -> TyVarBndr_ flag
    kindedTVFlag Name
    n Specificity
    InferredSpec Kind
    k

    -- | Construct a 'KindedTV' with a 'SpecifiedSpec'.
    kindedTVSpecified :: Name -> Kind -> TyVarBndrSpec
    kindedTVSpecified :: Name -> Kind -> TyVarBndrSpec
    kindedTVSpecified Name
    n Kind
    k = Name -> Specificity -> Kind -> TyVarBndrSpec
    forall flag. Name -> flag -> Kind -> TyVarBndr_ flag
    kindedTVFlag Name
    n Specificity
    SpecifiedSpec Kind
    k

    -- | Construct a 'KindedTV' with a 'BndrReq'.
    kindedTVReq :: Name -> Kind -> TyVarBndrVis
    kindedTVReq :: Name -> Kind -> TyVarBndrVis
    kindedTVReq Name
    n Kind
    k = Name -> BndrVis -> Kind -> TyVarBndrVis
    forall flag. Name -> flag -> Kind -> TyVarBndr_ flag
    kindedTVFlag Name
    n BndrVis
    bndrReq Kind
    k

    -- | Construct a 'KindedTV' with a 'BndrInvis'.
    kindedTVInvis :: Name -> Kind -> TyVarBndrVis
    kindedTVInvis :: Name -> Kind -> TyVarBndrVis
    kindedTVInvis Name
    n Kind
    k = Name -> BndrVis -> Kind -> TyVarBndrVis
    forall flag. Name -> flag -> Kind -> TyVarBndr_ flag
    kindedTVFlag Name
    n BndrVis
    bndrInvis Kind
    k

    -- | Case analysis for a 'TyVarBndr'. If the value is a @'PlainTV' n _@, apply
    -- the first function to @n@; if it is @'KindedTV' n _ k@, apply the second
    -- function to @n@ and @k@.
    elimTV :: (Name -> r) -> (Name -> Kind -> r) -> TyVarBndr_ flag -> r
    #if MIN_VERSION_template_haskell(2,17,0)
    elimTV :: forall r flag.
    (Name -> r) -> (Name -> Kind -> r) -> TyVarBndr_ flag -> r
    elimTV Name -> r
    ptv Name -> Kind -> r
    _ktv (PlainTV Name
    n flag
    _)    = Name -> r
    ptv Name
    n
    elimTV Name -> r
    _ptv Name -> Kind -> r
    ktv (KindedTV Name
    n flag
    _ Kind
    k) = Name -> Kind -> r
    ktv Name
    n Kind
    k
    #else
    elimTV ptv _ktv (PlainTV n)    = ptv n
    elimTV _ptv ktv (KindedTV n k) = ktv n k
    #endif

    -- | Case analysis for a 'TyVarBndr' that includes @flag@s in the continuation
    -- arguments. Note that 'TyVarBndr's did not include @flag@s prior to
    -- @template-haskell-2.17.0.0@, so on older versions of @template-haskell@,
    -- these @flag@s instead become @()@.
    #if MIN_VERSION_template_haskell(2,17,0)
    elimTVFlag :: (Name -> flag -> r) -> (Name -> flag -> Kind -> r) -> TyVarBndr_ flag -> r
    elimTVFlag :: forall flag r.
    (Name -> flag -> r)
    -> (Name -> flag -> Kind -> r) -> TyVarBndr_ flag -> r
    elimTVFlag Name -> flag -> r
    ptv Name -> flag -> Kind -> r
    _ktv (PlainTV Name
    n flag
    flag)    = Name -> flag -> r
    ptv Name
    n flag
    flag
    elimTVFlag Name -> flag -> r
    _ptv Name -> flag -> Kind -> r
    ktv (KindedTV Name
    n flag
    flag Kind
    k) = Name -> flag -> Kind -> r
    ktv Name
    n flag
    flag Kind
    k
    #else
    elimTVFlag :: (Name -> () -> r) -> (Name -> () -> Kind -> r) -> TyVarBndr_ flag -> r
    elimTVFlag ptv _ktv (PlainTV n)    = ptv n ()
    elimTVFlag _ptv ktv (KindedTV n k) = ktv n () k
    #endif

    -- | Map over the components of a 'TyVarBndr'.
    mapTV :: (Name -> Name) -> (flag -> flag') -> (Kind -> Kind)
          -> TyVarBndr_ flag -> TyVarBndr_ flag'
    #if MIN_VERSION_template_haskell(2,17,0)
    mapTV :: forall flag flag'.
    (Name -> Name)
    -> (flag -> flag')
    -> (Kind -> Kind)
    -> TyVarBndr_ flag
    -> TyVarBndr_ flag'
    mapTV Name -> Name
    fn flag -> flag'
    fflag Kind -> Kind
    _fkind (PlainTV  Name
    n flag
    flag)      = Name -> flag' -> TyVarBndr flag'
    forall flag. Name -> flag -> TyVarBndr_ flag
    PlainTV  (Name -> Name
    fn Name
    n) (flag -> flag'
    fflag flag
    flag)
    mapTV Name -> Name
    fn flag -> flag'
    fflag  Kind -> Kind
    fkind (KindedTV Name
    n flag
    flag Kind
    kind) = Name -> flag' -> Kind -> TyVarBndr flag'
    forall flag. Name -> flag -> Kind -> TyVarBndr_ flag
    KindedTV (Name -> Name
    fn Name
    n) (flag -> flag'
    fflag flag
    flag) (Kind -> Kind
    fkind Kind
    kind)
    #else
    mapTV fn _fflag _fkind (PlainTV  n)      = PlainTV  (fn n)
    mapTV fn _fflag  fkind (KindedTV n kind) = KindedTV (fn n) (fkind kind)
    #endif

    -- | Map over the 'Name' of a 'TyVarBndr'.
    mapTVName :: (Name -> Name) -> TyVarBndr_ flag -> TyVarBndr_ flag
    mapTVName :: forall flag. (Name -> Name) -> TyVarBndr_ flag -> TyVarBndr_ flag
    mapTVName Name -> Name
    fname = (Name -> Name)
    -> (flag -> flag)
    -> (Kind -> Kind)
    -> TyVarBndr_ flag
    -> TyVarBndr_ flag
    forall flag flag'.
    (Name -> Name)
    -> (flag -> flag')
    -> (Kind -> Kind)
    -> TyVarBndr_ flag
    -> TyVarBndr_ flag'
    mapTV Name -> Name
    fname flag -> flag
    forall a. a -> a
    id Kind -> Kind
    forall a. a -> a
    id

    -- | Map over the @flag@ of a 'TyVarBndr'.
    mapTVFlag :: (flag -> flag') -> TyVarBndr_ flag -> TyVarBndr_ flag'
    #if MIN_VERSION_template_haskell(2,17,0)
    mapTVFlag :: forall flag flag'.
    (flag -> flag') -> TyVarBndr_ flag -> TyVarBndr_ flag'
    mapTVFlag = (flag -> flag') -> TyVarBndr flag -> TyVarBndr flag'
    forall flag flag'.
    (flag -> flag') -> TyVarBndr_ flag -> TyVarBndr_ flag'
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap
    #else
    mapTVFlag _ = id
    #endif

    -- | Map over the 'Kind' of a 'TyVarBndr'.
    mapTVKind :: (Kind -> Kind) -> TyVarBndr_ flag -> TyVarBndr_ flag
    mapTVKind :: forall flag. (Kind -> Kind) -> TyVarBndr_ flag -> TyVarBndr_ flag
    mapTVKind Kind -> Kind
    fkind = (Name -> Name)
    -> (flag -> flag)
    -> (Kind -> Kind)
    -> TyVarBndr_ flag
    -> TyVarBndr_ flag
    forall flag flag'.
    (Name -> Name)
    -> (flag -> flag')
    -> (Kind -> Kind)
    -> TyVarBndr_ flag
    -> TyVarBndr_ flag'
    mapTV Name -> Name
    forall a. a -> a
    id flag -> flag
    forall a. a -> a
    id Kind -> Kind
    fkind

    -- | Traverse the components of a 'TyVarBndr'.
    traverseTV :: Applicative f
               => (Name -> f Name) -> (flag -> f flag') -> (Kind -> f Kind)
               -> TyVarBndr_ flag -> f (TyVarBndr_ flag')
    #if MIN_VERSION_template_haskell(2,17,0)
    traverseTV :: forall (f :: * -> *) flag flag'.
    Applicative f =>
    (Name -> f Name)
    -> (flag -> f flag')
    -> (Kind -> f Kind)
    -> TyVarBndr_ flag
    -> f (TyVarBndr_ flag')
    traverseTV Name -> f Name
    fn flag -> f flag'
    fflag Kind -> f Kind
    _fkind (PlainTV Name
    n flag
    flag) =
      (Name -> flag' -> TyVarBndr_ flag')
    -> f Name -> f flag' -> f (TyVarBndr_ flag')
    forall a b c. (a -> b -> c) -> f a -> f b -> f c
    forall (f :: * -> *) a b c.
    Applicative f =>
    (a -> b -> c) -> f a -> f b -> f c
    liftA2 Name -> flag' -> TyVarBndr_ flag'
    forall flag. Name -> flag -> TyVarBndr_ flag
    PlainTV (Name -> f Name
    fn Name
    n) (flag -> f flag'
    fflag flag
    flag)
    traverseTV Name -> f Name
    fn flag -> f flag'
    fflag Kind -> f Kind
    fkind (KindedTV Name
    n flag
    flag Kind
    kind) =
      (Name -> flag' -> Kind -> TyVarBndr_ flag')
    -> f Name -> f flag' -> f Kind -> f (TyVarBndr_ flag')
    forall (f :: * -> *) a b c d.
    Applicative f =>
    (a -> b -> c -> d) -> f a -> f b -> f c -> f d
    liftA3 Name -> flag' -> Kind -> TyVarBndr_ flag'
    forall flag. Name -> flag -> Kind -> TyVarBndr_ flag
    KindedTV (Name -> f Name
    fn Name
    n) (flag -> f flag'
    fflag flag
    flag) (Kind -> f Kind
    fkind Kind
    kind)
    #else
    traverseTV fn _fflag _fkind (PlainTV n) =
      PlainTV <$> fn n
    traverseTV fn _fflag fkind (KindedTV n kind) =
      liftA2 KindedTV (fn n) (fkind kind)
    #endif

    -- | Traverse the 'Name' of a 'TyVarBndr'.
    traverseTVName :: Functor f
                   => (Name -> f Name)
                   -> TyVarBndr_ flag -> f (TyVarBndr_ flag)
    #if MIN_VERSION_template_haskell(2,17,0)
    traverseTVName :: forall (f :: * -> *) flag.
    Functor f =>
    (Name -> f Name) -> TyVarBndr_ flag -> f (TyVarBndr_ flag)
    traverseTVName Name -> f Name
    fn (PlainTV Name
    n flag
    flag) =
      (\Name
    n' -> Name -> flag -> TyVarBndr flag
    forall flag. Name -> flag -> TyVarBndr_ flag
    PlainTV Name
    n' flag
    flag) (Name -> TyVarBndr flag) -> f Name -> f (TyVarBndr flag)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Name -> f Name
    fn Name
    n
    traverseTVName Name -> f Name
    fn (KindedTV Name
    n flag
    flag Kind
    kind) =
      (\Name
    n' -> Name -> flag -> Kind -> TyVarBndr flag
    forall flag. Name -> flag -> Kind -> TyVarBndr_ flag
    KindedTV Name
    n' flag
    flag Kind
    kind) (Name -> TyVarBndr flag) -> f Name -> f (TyVarBndr flag)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Name -> f Name
    fn Name
    n
    #else
    traverseTVName fn (PlainTV n) =
      PlainTV <$> fn n
    traverseTVName fn (KindedTV n kind) =
      (\n' -> KindedTV n' kind) <$> fn n
    #endif

    -- | Traverse the @flag@ of a 'TyVarBndr'.
    traverseTVFlag :: Applicative f
                   => (flag -> f flag')
                   -> TyVarBndr_ flag -> f (TyVarBndr_ flag')
    #if MIN_VERSION_template_haskell(2,17,0)
    traverseTVFlag :: forall (f :: * -> *) flag flag'.
    Applicative f =>
    (flag -> f flag') -> TyVarBndr_ flag -> f (TyVarBndr_ flag')
    traverseTVFlag flag -> f flag'
    fflag (PlainTV Name
    n flag
    flag) =
      Name -> flag' -> TyVarBndr flag'
    forall flag. Name -> flag -> TyVarBndr_ flag
    PlainTV Name
    n (flag' -> TyVarBndr flag') -> f flag' -> f (TyVarBndr flag')
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> flag -> f flag'
    fflag flag
    flag
    traverseTVFlag flag -> f flag'
    fflag (KindedTV Name
    n flag
    flag Kind
    kind) =
      (\flag'
    flag' -> Name -> flag' -> Kind -> TyVarBndr flag'
    forall flag. Name -> flag -> Kind -> TyVarBndr_ flag
    KindedTV Name
    n flag'
    flag' Kind
    kind) (flag' -> TyVarBndr flag') -> f flag' -> f (TyVarBndr flag')
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> flag -> f flag'
    fflag flag
    flag
    #else
    traverseTVFlag _ = pure
    #endif

    -- | Traverse the 'Kind' of a 'TyVarBndr'.
    traverseTVKind :: Applicative f
                   => (Kind -> f Kind)
                   -> TyVarBndr_ flag -> f (TyVarBndr_ flag)
    #if MIN_VERSION_template_haskell(2,17,0)
    traverseTVKind :: forall (f :: * -> *) flag.
    Applicative f =>
    (Kind -> f Kind) -> TyVarBndr_ flag -> f (TyVarBndr_ flag)
    traverseTVKind Kind -> f Kind
    _fkind tvb :: TyVarBndr_ flag
    tvb@PlainTV{} =
      TyVarBndr_ flag -> f (TyVarBndr_ flag)
    forall a. a -> f a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure TyVarBndr_ flag
    tvb
    traverseTVKind Kind -> f Kind
    fkind (KindedTV Name
    n flag
    flag Kind
    kind) =
      Name -> flag -> Kind -> TyVarBndr_ flag
    forall flag. Name -> flag -> Kind -> TyVarBndr_ flag
    KindedTV Name
    n flag
    flag (Kind -> TyVarBndr_ flag) -> f Kind -> f (TyVarBndr_ flag)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Kind -> f Kind
    fkind Kind
    kind
    #else
    traverseTVKind _fkind tvb@PlainTV{} =
      pure tvb
    traverseTVKind fkind (KindedTV n kind) =
      KindedTV n <$> fkind kind
    #endif

    -- | Map over the components of a 'TyVarBndr' in a monadic fashion.
    --
    -- This is the same as 'traverseTV', but with a 'Monad' constraint. This is
    -- mainly useful for use with old versions of @base@ where 'Applicative' was
    -- not a superclass of 'Monad'.
    mapMTV :: Monad m
           => (Name -> m Name) -> (flag -> m flag') -> (Kind -> m Kind)
           -> TyVarBndr_ flag -> m (TyVarBndr_ flag')
    #if MIN_VERSION_template_haskell(2,17,0)
    mapMTV :: forall (m :: * -> *) flag flag'.
    Monad m =>
    (Name -> m Name)
    -> (flag -> m flag')
    -> (Kind -> m Kind)
    -> TyVarBndr_ flag
    -> m (TyVarBndr_ flag')
    mapMTV Name -> m Name
    fn flag -> m flag'
    fflag Kind -> m Kind
    _fkind (PlainTV Name
    n flag
    flag) =
      (Name -> flag' -> TyVarBndr_ flag')
    -> m Name -> m flag' -> m (TyVarBndr_ flag')
    forall (m :: * -> *) a1 a2 r.
    Monad m =>
    (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
    liftM2 Name -> flag' -> TyVarBndr_ flag'
    forall flag. Name -> flag -> TyVarBndr_ flag
    PlainTV (Name -> m Name
    fn Name
    n) (flag -> m flag'
    fflag flag
    flag)
    mapMTV Name -> m Name
    fn flag -> m flag'
    fflag Kind -> m Kind
    fkind (KindedTV Name
    n flag
    flag Kind
    kind) =
      (Name -> flag' -> Kind -> TyVarBndr_ flag')
    -> m Name -> m flag' -> m Kind -> m (TyVarBndr_ flag')
    forall (m :: * -> *) a1 a2 a3 r.
    Monad m =>
    (a1 -> a2 -> a3 -> r) -> m a1 -> m a2 -> m a3 -> m r
    liftM3 Name -> flag' -> Kind -> TyVarBndr_ flag'
    forall flag. Name -> flag -> Kind -> TyVarBndr_ flag
    KindedTV (Name -> m Name
    fn Name
    n) (flag -> m flag'
    fflag flag
    flag) (Kind -> m Kind
    fkind Kind
    kind)
    #else
    mapMTV fn _fflag _fkind (PlainTV n) =
      liftM PlainTV (fn n)
    mapMTV fn _fflag fkind (KindedTV n kind) =
      liftM2 KindedTV (fn n) (fkind kind)
    #endif

    -- | Map over the 'Name' of a 'TyVarBndr' in a monadic fashion.
    --
    -- This is the same as 'traverseTVName', but with a 'Monad' constraint. This is
    -- mainly useful for use with old versions of @base@ where 'Applicative' was
    -- not a superclass of 'Monad'.
    mapMTVName :: Monad m
               => (Name -> m Name)
               -> TyVarBndr_ flag -> m (TyVarBndr_ flag)
    #if MIN_VERSION_template_haskell(2,17,0)
    mapMTVName :: forall (m :: * -> *) flag.
    Monad m =>
    (Name -> m Name) -> TyVarBndr_ flag -> m (TyVarBndr_ flag)
    mapMTVName Name -> m Name
    fn (PlainTV Name
    n flag
    flag) =
      (Name -> TyVarBndr flag) -> m Name -> m (TyVarBndr flag)
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    liftM (\Name
    n' -> Name -> flag -> TyVarBndr flag
    forall flag. Name -> flag -> TyVarBndr_ flag
    PlainTV Name
    n' flag
    flag) (Name -> m Name
    fn Name
    n)
    mapMTVName Name -> m Name
    fn (KindedTV Name
    n flag
    flag Kind
    kind) =
      (Name -> TyVarBndr flag) -> m Name -> m (TyVarBndr flag)
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    liftM (\Name
    n' -> Name -> flag -> Kind -> TyVarBndr flag
    forall flag. Name -> flag -> Kind -> TyVarBndr_ flag
    KindedTV Name
    n' flag
    flag Kind
    kind) (Name -> m Name
    fn Name
    n)
    #else
    mapMTVName fn (PlainTV n) =
      liftM PlainTV (fn n)
    mapMTVName fn (KindedTV n kind) =
      liftM (\n' -> KindedTV n' kind) (fn n)
    #endif

    -- | Map over the @flag@ of a 'TyVarBndr' in a monadic fashion.
    --
    -- This is the same as 'traverseTVFlag', but with a 'Monad' constraint. This is
    -- mainly useful for use with old versions of @base@ where 'Applicative' was
    -- not a superclass of 'Monad'.
    mapMTVFlag :: Monad m
               => (flag -> m flag')
               -> TyVarBndr_ flag -> m (TyVarBndr_ flag')
    #if MIN_VERSION_template_haskell(2,17,0)
    mapMTVFlag :: forall (m :: * -> *) flag flag'.
    Monad m =>
    (flag -> m flag') -> TyVarBndr_ flag -> m (TyVarBndr_ flag')
    mapMTVFlag flag -> m flag'
    fflag (PlainTV Name
    n flag
    flag) =
      (flag' -> TyVarBndr_ flag') -> m flag' -> m (TyVarBndr_ flag')
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    liftM (Name -> flag' -> TyVarBndr_ flag'
    forall flag. Name -> flag -> TyVarBndr_ flag
    PlainTV Name
    n) (flag -> m flag'
    fflag flag
    flag)
    mapMTVFlag flag -> m flag'
    fflag (KindedTV Name
    n flag
    flag Kind
    kind) =
      (flag' -> TyVarBndr_ flag') -> m flag' -> m (TyVarBndr_ flag')
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    liftM (\flag'
    flag' -> Name -> flag' -> Kind -> TyVarBndr_ flag'
    forall flag. Name -> flag -> Kind -> TyVarBndr_ flag
    KindedTV Name
    n flag'
    flag' Kind
    kind) (flag -> m flag'
    fflag flag
    flag)
    #else
    mapMTVFlag _ = return
    #endif

    -- | Map over the 'Kind' of a 'TyVarBndr' in a monadic fashion.
    --
    -- This is the same as 'traverseTVKind', but with a 'Monad' constraint. This is
    -- mainly useful for use with old versions of @base@ where 'Applicative' was
    -- not a superclass of 'Monad'.
    mapMTVKind :: Monad m
               => (Kind -> m Kind)
               -> TyVarBndr_ flag -> m (TyVarBndr_ flag)
    #if MIN_VERSION_template_haskell(2,17,0)
    mapMTVKind :: forall (m :: * -> *) flag.
    Monad m =>
    (Kind -> m Kind) -> TyVarBndr_ flag -> m (TyVarBndr_ flag)
    mapMTVKind Kind -> m Kind
    _fkind tvb :: TyVarBndr_ flag
    tvb@PlainTV{} =
      TyVarBndr_ flag -> m (TyVarBndr_ flag)
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return TyVarBndr_ flag
    tvb
    mapMTVKind Kind -> m Kind
    fkind (KindedTV Name
    n flag
    flag Kind
    kind) =
      (Kind -> TyVarBndr_ flag) -> m Kind -> m (TyVarBndr_ flag)
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    liftM (Name -> flag -> Kind -> TyVarBndr_ flag
    forall flag. Name -> flag -> Kind -> TyVarBndr_ flag
    KindedTV Name
    n flag
    flag) (Kind -> m Kind
    fkind Kind
    kind)
    #else
    mapMTVKind _fkind tvb@PlainTV{} =
      return tvb
    mapMTVKind fkind (KindedTV n kind) =
      liftM (KindedTV n) (fkind kind)
    #endif

    -- | Set the flag in a list of 'TyVarBndr's. This is often useful in contexts
    -- where one needs to re-use a list of 'TyVarBndr's from one flag setting to
    -- another flag setting. For example, in order to re-use the 'TyVarBndr's bound
    -- by a 'DataD' in a 'ForallT', one can do the following:
    --
    -- @
    -- case x of
    --   'DataD' _ _ tvbs _ _ _ ->
    --     'ForallT' ('changeTVFlags' 'SpecifiedSpec' tvbs) ...
    -- @
    changeTVFlags :: newFlag -> [TyVarBndr_ oldFlag] -> [TyVarBndr_ newFlag]
    #if MIN_VERSION_template_haskell(2,17,0)
    changeTVFlags :: forall newFlag oldFlag.
    newFlag -> [TyVarBndr_ oldFlag] -> [TyVarBndr_ newFlag]
    changeTVFlags newFlag
    newFlag = (TyVarBndr_ oldFlag -> TyVarBndr_ newFlag)
    -> [TyVarBndr_ oldFlag] -> [TyVarBndr_ newFlag]
    forall a b. (a -> b) -> [a] -> [b]
    map (newFlag
    newFlag newFlag -> TyVarBndr_ oldFlag -> TyVarBndr_ newFlag
    forall a b. a -> TyVarBndr b -> TyVarBndr a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$)
    #else
    changeTVFlags _ = id
    #endif

    -- | Extract the type variable name from a 'TyVarBndr', ignoring the
    -- kind signature if one exists.
    tvName :: TyVarBndr_ flag -> Name
    tvName :: forall flag. TyVarBndr_ flag -> Name
    tvName = (Name -> Name) -> (Name -> Kind -> Name) -> TyVarBndr_ flag -> Name
    forall r flag.
    (Name -> r) -> (Name -> Kind -> r) -> TyVarBndr_ flag -> r
    elimTV Name -> Name
    forall a. a -> a
    id (\Name
    n Kind
    _ -> Name
    n)

    -- | Extract the kind from a 'TyVarBndr'. Assumes 'PlainTV' has kind @*@.
    tvKind :: TyVarBndr_ flag -> Kind
    tvKind :: forall flag. TyVarBndr_ flag -> Kind
    tvKind = (Name -> Kind) -> (Name -> Kind -> Kind) -> TyVarBndr_ flag -> Kind
    forall r flag.
    (Name -> r) -> (Name -> Kind -> r) -> TyVarBndr_ flag -> r
    elimTV (\Name
    _ -> Kind
    starK) (\Name
    _ Kind
    k -> Kind
    k)

    -- | Extract the @flag@ from a 'TyVarBndr'. Note that 'TyVarBndr's did not
    -- include @flag@s prior to @template-haskell-2.17.0.0@, so on older versions of
    -- @template-haskell@, this functions instead returns @()@.
    #if MIN_VERSION_template_haskell(2,17,0)
    tvFlag :: TyVarBndr_ flag -> flag
    tvFlag :: forall flag. TyVarBndr_ flag -> flag
    tvFlag = (Name -> flag -> flag)
    -> (Name -> flag -> Kind -> flag) -> TyVarBndr_ flag -> flag
    forall flag r.
    (Name -> flag -> r)
    -> (Name -> flag -> Kind -> r) -> TyVarBndr_ flag -> r
    elimTVFlag (\Name
    _ flag
    flag -> flag
    flag) (\Name
    _ flag
    flag Kind
    _ -> flag
    flag)
    #else
    tvFlag :: TyVarBndr_ flag -> ()
    tvFlag _ = ()
    #endif