content: {-# LANGUAGE DataKinds #-}
  {-# LANGUAGE PolyKinds #-}
  {-# LANGUAGE TypeFamilies #-}
  {-# LANGUAGE TypeOperators #-}
  {-# LANGUAGE UndecidableInstances #-}
  
  -- | @'FixupMetaData' a g@ copies the metadata from the
  -- @"GHC.Generics".'GHC.Generics.Generic'@ representation of @a@ to the
  -- representation @g@.
  --
  -- @'FixupMetaData1' f g@ does something similar when @f 'Any'@ is an instance
  -- of @Generic@ and @g@ is a @Rep1@. See the individual type documentation
  -- for details.
  --
  -- This is intended to help users instantiate 'Rep' and 'Rep1' for types with
  -- nonlinear or multiplicity-polymorphic fields.
  --
  -- == Suggested use
  --
  -- You will need to derive a @"GHC.Generics.Generic"@ instance for the
  -- type. This is used to obtain the correct metadata.
  --
  -- Next you need to construct a @Rep@ and/or @Rep1@ for your type, ignoring the
  -- metadata.
  --
  -- Constructing the actual representations can be a bit annoying, but GHC can
  -- help.
  --
  -- === For 'Rep'
  --
  -- Once you have derived  @"GHC.Generics".'GHC.Generics.Generic'@ for your
  -- type, define a value like
  --
  -- @
  -- test :: Rep T a
  -- test = _
  -- @
  --
  -- Then compile. The stripped representation you need will be in the error
  -- message.
  --
  -- === For 'Rep1'
  --
  -- Construct a type with the same shape as the one you wish to
  -- instantiate, but with only linear fields. Strictness annotations
  -- and @UNPACK@ pragmas are irrelevant here.
  --
  -- Instantiate @"Generics.Linear".'Generic1'@ for the lookalike using
  -- 'Generics.Linear.TH.deriveGeneric1' and follow the same procedure
  -- as above (but with @'Rep1' T@, of course) to get a metadata-stripped
  -- representation.
  --
  -- === For either
  --
  -- To avoid confusion, replace at least the package and module names in the
  -- representation with 'Any'. Wrap @MP1@ around any nonlinear/representation
  -- polymorphic fields, just under the @S1@ type constructor. The first type
  -- argument of @MP1@ will indicate the multiplicity.
  module Prelude.Linear.GenericUtil
    ( FixupMetaData,
      FixupMetaData1,
      RemoveMetaData,
    )
  where
  
  import Data.Kind (Type)
  import qualified GHC.Generics
  import GHC.TypeLits
  import Generics.Linear
  
  -- | @FixupMetaData a g@ copies the metadata from the
  -- @"GHC.Generics".'GHC.Generics.Generic'@ representation of @a@ to the
  -- representation @g@. It also checks that the structure of @Rep a@ is the
  -- same as @g@, except that @g@ may have @MP1@ applications under some @S1@
  -- constructors.
  --
  -- === Example
  --
  -- @
  -- instance 'Generic' ('Prelude.Linear.Ur' a) where
  --   type Rep (Ur a) = FixupMetaData (Ur a)
  --         (D1 Any
  --           (C1 Any
  --             (S1 Any
  --               (MP1 \'Many (Rec0 a)))))
  -- @
  type FixupMetaData (a :: Type) (g :: Type -> Type) =
    Fixup (GHC.Generics.Rep a) g
  
  -- | @FixupMetaData1 f g@ copies the metadata from the
  -- @"GHC.Generics".'GHC.Generics.Generic'@ representation of @f 'Any'@
  -- to the representation @g@. It also checks that the overall structure of
  -- @Rep (f 'Any')@ is the same as @g@, but does not check that their fields
  -- match.
  --
  -- === Example
  --
  -- @
  -- instance 'Generic1' 'Prelude.Linear.Ur' where
  --   type Rep1 Ur = FixupMetaData1 Ur
  --          (D1 Any
  --             (C1 Any
  --                (S1 Any
  --                   (MP1 \'Many Par1))))
  -- @
  type FixupMetaData1 (f :: k -> Type) (g :: k -> Type) =
    Fixup1 (GHC.Generics.Rep (f Any)) g
  
  type family Fixup (f :: Type -> Type) (g :: Type -> Type) :: Type -> Type where
    Fixup (D1 c f) (D1 _c g) = D1 c (Fixup f g)
    Fixup (C1 c f) (C1 _c g) = C1 c (Fixup f g)
    Fixup (S1 c f) (S1 _c (MP1 m f)) = S1 c (MP1 m f)
    Fixup (S1 c f) (S1 _c f) = S1 c f
    Fixup (f :*: g) (f' :*: g') = Fixup f f' :*: Fixup g g'
    Fixup (f :+: g) (f' :+: g') = Fixup f f' :+: Fixup g g'
    Fixup V1 V1 = V1
    Fixup _ _ = TypeError ('Text "FixupMetaData: representations do not match.")
  
  type family Fixup1 (f :: Type -> Type) (g :: k -> Type) :: k -> Type where
    Fixup1 (D1 c f) (D1 _c g) = D1 c (Fixup1 f g)
    Fixup1 (C1 c f) (C1 _c g) = C1 c (Fixup1 f g)
    Fixup1 (f :*: g) (f' :*: g') = Fixup1 f f' :*: Fixup1 g g'
    Fixup1 (f :+: g) (f' :+: g') = Fixup1 f f' :+: Fixup1 g g'
    Fixup1 (S1 c _f) (S1 _c g) = S1 c g
    Fixup1 V1 V1 = V1
    Fixup1 _ _ = TypeError ('Text "Fixup1MetaData1: representations do not match.")
  
  type family RemoveMetaData (f :: k -> Type) :: k -> Type where
    RemoveMetaData (D1 _c f) = D1 Any (RemoveMetaData f)
    RemoveMetaData (C1 _c f) = C1 Any (RemoveMetaData f)
    RemoveMetaData (S1 _c f) = S1 Any f
    RemoveMetaData (f :*: g) = RemoveMetaData f :*: RemoveMetaData g
    RemoveMetaData (f :+: g) = RemoveMetaData f :+: RemoveMetaData g
    RemoveMetaData x = x
  
  type family Any :: k
  