    {-# OPTIONS_HADDOCK hide          #-}
    {-# LANGUAGE DataKinds            #-}
    {-# LANGUAGE FlexibleContexts     #-}
    {-# LANGUAGE FlexibleInstances    #-}
    {-# LANGUAGE InstanceSigs         #-}
    {-# LANGUAGE PolyKinds            #-}
    {-# LANGUAGE ScopedTypeVariables  #-}
    {-# LANGUAGE TypeFamilies         #-}
    {-# LANGUAGE TypeOperators        #-}
    {-# LANGUAGE UndecidableInstances #-}

    --------------------------------------------------------------------------------
    -- |
    -- Module      : Data.Generics.Internal.GenericN
    -- Copyright   : (C) 2020 Csongor Kiss
    -- License     : BSD3
    -- Maintainer  : Csongor Kiss <kiss.csongor.kiss@gmail.com>
    -- Stability   : experimental
    -- Portability : non-portable
    --
    -- Generic representation of types with multiple parameters
    --
    --------------------------------------------------------------------------------

    module Data.Generics.Internal.GenericN
      ( Param (..)
      , Rec (Rec, unRec)
      , GenericN (..)
      ) where

    import Data.Kind
    import GHC.Generics
    import GHC.TypeLits
    import Data.Coerce

    data family Param :: Nat -> j -> k

    newtype instance Param n (a :: Type)
      = StarParam { forall (n :: Nat) a. Param n a -> a
    getStarParam :: a}

    type family Indexed (t :: k) (i :: Nat) :: k where
      Indexed (t a) i = Indexed t (i + 1) (Param i a)
      Indexed t _     = t

    newtype Rec (p :: Type) a x = Rec { forall {k} p a (x :: k). Rec p a x -> K1 R a x
    unRec :: K1 R a x }

    class
      ( Coercible (Rep a) (RepN a)
      , Generic a
      ) => GenericN (a :: Type) where
      type family RepN (a :: Type) :: Type -> Type
      type instance RepN a = Rep (Indexed a 0)
      toN :: RepN a x -> a
      fromN :: a -> RepN a x

    instance
      ( Coercible (Rep a) (RepN a)
      , Generic a
      ) => GenericN a where
      toN :: forall x. RepN a x -> a
      toN :: forall x. RepN a x -> a
    toN   = (Rep a x -> a) -> Rep (Indexed a 0) x -> a
    forall a b. Coercible a b => a -> b
    coerce (Rep a x -> a
    forall a x. Generic a => Rep a x -> a
    forall x. Rep a x -> a
    to :: Rep a x -> a)
      {-# INLINE toN #-}

      fromN :: forall x. a -> RepN a x
      fromN :: forall x. a -> RepN a x
    fromN = (a -> Rep a x) -> a -> Rep (Indexed a 0) x
    forall a b. Coercible a b => a -> b
    coerce (a -> Rep a x
    forall x. a -> Rep a x
    forall a x. Generic a => a -> Rep a x
    from :: a -> Rep a x)
      {-# INLINE fromN #-}