{-# LANGUAGE EmptyCase             #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE KindSignatures        #-}
{-# LANGUAGE LambdaCase            #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternSynonyms       #-}
{-# LANGUAGE RankNTypes            #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE StandaloneDeriving    #-}
{-# LANGUAGE TupleSections         #-}
{-# LANGUAGE TypeApplications      #-}
{-# LANGUAGE TypeInType            #-}
{-# LANGUAGE TypeOperators         #-}
{-# LANGUAGE ViewPatterns          #-}
module Data.Type.List.Sublist (
  
  
    Prefix(..), IsPrefix, autoPrefix
  , takeRec, prefixLens, takeIndex, weakenIndex
  , prefixShape
  
  , Suffix(..), IsSuffix, autoSuffix
  , dropRec, suffixLens, dropIndex, shiftIndex
  
  , Append(..), IsAppend, autoAppend, withAppend
  , prefixToAppend, suffixToAppend
  , appendToPrefix, appendToSuffix, splitAppend
  , appendShape
  
  , splitRec, appendRec, splitRecIso
  , splitIndex
  
  
  , pattern AppendWit
  , appendWit, implyAppend, unAppendWit
  
  , pattern AppendWitV
  , appendWitV, implyAppendV, unAppendWitV
  
  , pattern AppendWit'
  , convertAppends
  , AppendedTo
  
  , Interleave(..), IsInterleave, autoInterleave
  , interleaveRec, unweaveRec, interleaveRecIso
  , injectIndexL, injectIndexR, unweaveIndex
  , interleavedIxes, swapInterleave
  , interleaveShapes
  
  , Subset(..), IsSubset, autoSubset
  , subsetComplement
  , interleaveRToSubset, interleaveLToSubset
  , subsetToInterleaveL, subsetToInterleaveR
  , subsetRec, getSubset
  , subsetShapes
  , subsetIxes
  , weakenSubsetIndex, strengthenSubsetIndex
  ) where
import           Data.Bifunctor
import           Data.Functor.Compose
import           Data.Kind
import           Data.Profunctor
import           Data.Singletons
import           Data.Singletons.Decide
import           Data.Singletons.Prelude.List
import           Data.Singletons.Sigma
import           Data.Type.Functor.Product
import           Data.Type.Predicate
import           Data.Type.Predicate.Auto
import           Data.Type.Predicate.Param
import           Data.Vinyl hiding            ((:~:))
import           GHC.Generics                 ((:+:)(..))
import           Lens.Micro hiding            ((%~))
import           Lens.Micro.Extras
import qualified Data.Vinyl.Recursive         as VR
import qualified Data.Vinyl.TypeLevel         as V
data Prefix :: [k] -> [k] -> Type where
    PreZ :: Prefix '[] as
    PreS :: Prefix  as bs -> Prefix  (a ': as) (a ': bs)
deriving instance Show (Prefix as bs)
prefixLens :: Prefix as bs -> Lens' (Rec f bs) (Rec f as)
prefixLens p = prefixToAppend p $ \a -> splitRecIso a . _1
takeRec :: Prefix as bs -> Rec f bs -> Rec f as
takeRec p = view (prefixLens p)
type IsPrefix as = TyPred (Prefix as)
instance Auto (IsPrefix '[]) bs where
    auto = PreZ
instance Auto (IsPrefix as) bs => Auto (IsPrefix (a ': as)) (a ': bs) where
    auto = PreS (auto @_ @(IsPrefix as) @bs)
instance (SDecide k, SingI (as :: [k])) => Decidable (IsPrefix as) where
    decide = case sing @as of
      SNil         -> \_ -> Proved PreZ
      x `SCons` (Sing :: Sing as') -> \case
        SNil -> Disproved $ \case {}
        y `SCons` (ys :: Sing bs') -> case x %~ y of
          Proved Refl -> case decide @(IsPrefix as') ys of
            Proved p -> Proved (PreS p)
            Disproved v -> Disproved $ \case
              PreS p -> v p
          Disproved v -> Disproved $ \case
            PreS _ -> v Refl
autoPrefix :: forall as bs. Auto (IsPrefix as) bs => Prefix as bs
autoPrefix = auto @_ @(IsPrefix as) @bs
prefixShape
    :: Prefix as bs
    -> Shape [] as
prefixShape = \case
    PreZ   -> RNil
    PreS p -> Proxy :& prefixShape p
data Suffix :: [k] -> [k] -> Type where
    SufZ :: Suffix as as
    SufS :: Suffix as bs -> Suffix as (b ': bs)
deriving instance Show (Suffix as bs)
type IsSuffix as = TyPred (Suffix as)
instance Auto (IsSuffix '[]) '[] where
    auto = SufZ
instance {-# OVERLAPPABLE #-} Auto (IsSuffix (a ': as)) (a ': as) where
    auto = SufZ
instance {-# OVERLAPPABLE #-} Auto (IsSuffix as) bs => Auto (IsSuffix as) (b ': bs) where
    auto = SufS (auto @_ @(IsSuffix as) @bs)
instance (SDecide k, SingI (as :: [k])) => Decidable (IsSuffix as) where
    decide = \case
      SNil -> case sing @as of
        SNil -> Proved SufZ
        _ `SCons` _ -> Disproved $ \case {}
      _ `SCons` ys -> case decide @(IsSuffix as) ys of
        Proved s    -> Proved $ SufS s
        Disproved v -> Disproved $ \case
          SufZ   -> error "help me"
          SufS s -> v s
autoSuffix :: forall as bs. Auto (IsSuffix as) bs => Suffix as bs
autoSuffix = auto @_ @(IsSuffix as) @bs
suffixLens :: Suffix as bs -> Lens' (Rec f bs) (Rec f as)
suffixLens p = suffixToAppend p $ \a -> splitRecIso a . _2
dropRec :: Suffix as bs -> Rec f bs -> Rec f as
dropRec p = view (suffixLens p)
data Append :: [k] -> [k] -> [k] -> Type where
    AppZ :: Append '[] as as
    AppS :: Append as bs cs -> Append (a ': as) bs (a ': cs)
deriving instance Show (Append as bs cs)
type IsAppend as bs = TyPred (Append as bs)
type AppendedTo as = TyPP (Append as)
instance Auto (IsAppend '[] as) as where
    auto = AppZ
instance Auto (IsAppend as bs) cs => Auto (IsAppend (a ': as) bs) (a ': cs) where
    auto = AppS (auto @_ @(IsAppend as bs) @cs)
instance (SDecide k, SingI (as :: [k]), SingI bs) => Decidable (IsAppend as bs) where
    decide = case sing @as of
      SNil         -> \cs -> case sing @bs %~ cs of
        Proved Refl -> Proved AppZ
        Disproved v -> Disproved $ \case
          AppZ -> v Refl
      x `SCons` (Sing :: Sing as') -> \case
        SNil -> Disproved $ \case {}
        y `SCons` (ys :: Sing bs') -> case x %~ y of
          Proved Refl -> case decide @(IsAppend as' bs) ys of
            Proved p -> Proved (AppS p)
            Disproved v -> Disproved $ \case
              AppS p -> v p
          Disproved v -> Disproved $ \case
            AppS _ -> v Refl
instance SingI as => Decidable (Found (AppendedTo as))
instance SingI as => Provable (Found (AppendedTo as)) where
    prove ys = withAppend (singProd (sing @as)) (singProd ys) $ \s x -> prodSing s :&: x
autoAppend :: forall as bs cs. Auto (IsAppend as bs) cs => Append as bs cs
autoAppend = auto @_ @(IsAppend as bs) @cs
appendWit :: Append as bs cs -> (as ++ bs) :~: cs
appendWit = \case
    AppZ   -> Refl
    AppS a -> case appendWit a of
      Refl -> Refl
unAppendWit
    :: (as ++ bs) ~ cs
    => Rec f as
    -> Rec f bs
    -> Append as bs cs
unAppendWit = \case
    RNil    -> \_   -> AppZ
    _ :& xs -> AppS . unAppendWit xs
pattern AppendWit :: forall as bs cs. (RecApplicative as, RecApplicative bs) => (as ++ bs) ~ cs => Append as bs cs
pattern AppendWit <- (appendWit @as @bs @cs -> Refl)
  where
    AppendWit = unAppendWit @as @bs @cs pureShape pureShape
{-# COMPLETE AppendWit #-}
implyAppend :: IsAppend as bs --> EqualTo (as ++ bs)
implyAppend _ = appendWit
appendWitV :: Append as bs cs -> (as V.++ bs) :~: cs
appendWitV = \case
    AppZ -> Refl
    AppS a -> case appendWitV a of
      Refl -> Refl
unAppendWitV
    :: (as V.++ bs) ~ cs
    => Rec f as
    -> Rec f bs
    -> Append as bs cs
unAppendWitV = \case
    RNil     -> \_   -> AppZ
    _ :& xs -> AppS . unAppendWitV xs
pattern AppendWitV :: forall as bs cs. (RecApplicative as, RecApplicative bs) => (as V.++ bs) ~ cs => Append as bs cs
pattern AppendWitV <- (appendWitV @as @bs @cs -> Refl)
  where
    AppendWitV = unAppendWitV @as @bs @cs pureShape pureShape
{-# COMPLETE AppendWitV #-}
pattern AppendWit' :: forall as bs cs. (RecApplicative as, RecApplicative bs) => ((as ++ bs) ~ cs, (as V.++ bs) ~ cs) => Append as bs cs
pattern AppendWit' <- ((\a -> (a,a)) -> (AppendWit, AppendWitV))
  where
    AppendWit' = AppendWit
{-# COMPLETE AppendWitV #-}
implyAppendV :: IsAppend as bs --> EqualTo (as V.++ bs)
implyAppendV _ = appendWitV
convertAppends :: Append as bs cs -> (as ++ bs) :~: (as V.++ bs)
convertAppends a = case appendWit a of
    Refl -> case appendWitV a of
      Refl -> Refl
withAppend :: Rec f as -> Rec f bs -> (forall cs. Rec f cs -> Append as bs cs -> r) -> r
withAppend = \case
    RNil -> \ys f -> f ys AppZ
    x :& xs -> \ys f -> withAppend xs ys $ \zs a ->
      f (x :& zs) (AppS a)
appendShape
    :: Append as bs cs
    -> Shape [] as
appendShape = \case
    AppZ   -> RNil
    AppS a -> Proxy :& appendShape a
splitRecIso
    :: (Profunctor p, Functor f)
    => Append as bs cs
    -> p (Rec g as, Rec g bs) (f (Rec g as, Rec g bs))
    -> p (Rec g cs)           (f (Rec g cs))
splitRecIso a = dimap (splitRec a) ((fmap . uncurry) (appendRec a))
splitRec
    :: Append as bs cs
    -> Rec f cs
    -> (Rec f as, Rec f bs)
splitRec = \case
    AppZ   -> (RNil,)
    AppS a -> \case
      x :& xs -> first (x :&) . splitRec a $ xs
appendRec
    :: Append as bs cs
    -> Rec f as
    -> Rec f bs
    -> Rec f cs
appendRec = \case
    AppZ   -> \_ -> id
    AppS a -> \case
      x :& xs -> (x :&) . appendRec a xs
prefixToAppend
    :: Prefix as cs
    -> (forall bs. Append as bs cs -> r)
    -> r
prefixToAppend = \case
    PreZ   -> ($ AppZ)
    PreS p -> \f -> prefixToAppend p (f . AppS)
suffixToAppend
    :: Suffix bs cs
    -> (forall as. Append as bs cs -> r)
    -> r
suffixToAppend = \case
    SufZ   -> ($ AppZ)
    SufS s -> \f -> suffixToAppend s (f . AppS)
splitAppend
    :: Append as bs cs
    -> (Prefix as cs, Suffix bs cs)
splitAppend = \case
    AppZ   -> (PreZ, SufZ)
    AppS a -> bimap PreS SufS . splitAppend $ a
appendToPrefix :: Append as bs cs -> Prefix as cs
appendToPrefix = \case
    AppZ   -> PreZ
    AppS a -> PreS . appendToPrefix $ a
appendToSuffix :: Append as bs cs -> Suffix bs cs
appendToSuffix = \case
    AppZ   -> SufZ
    AppS a -> SufS . appendToSuffix $ a
splitIndex
    :: Append as bs cs
    -> Index cs x
    -> Either (Index as x) (Index bs x)
splitIndex = \case
    AppZ   -> Right
    AppS a -> \case
      IZ   -> Left IZ
      IS i -> first IS . splitIndex a $ i
takeIndex
    :: Prefix as bs
    -> Index bs x
    -> Maybe (Index as x)
takeIndex p i = prefixToAppend p $ either Just (const Nothing)
                                 . (`splitIndex` i)
dropIndex
    :: Suffix as bs
    -> Index bs x
    -> Maybe (Index as x)
dropIndex s i = suffixToAppend s $ either (const Nothing) Just
                                 . (`splitIndex` i)
weakenIndex
    :: Prefix as bs
    -> Index as x
    -> Index bs x
weakenIndex = \case
    PreZ   -> \case {}
    PreS p -> \case
      IZ   -> IZ
      IS i -> IS (weakenIndex p i)
shiftIndex
    :: Suffix as bs
    -> Index as x
    -> Index bs x
shiftIndex = \case
    SufZ   -> id
    SufS s -> IS . shiftIndex s
data Interleave :: [k] -> [k] -> [k] -> Type where
    IntZ :: Interleave '[] '[] '[]
    IntL :: Interleave as bs cs -> Interleave (a ': as) bs        (a ': cs)
    IntR :: Interleave as bs cs -> Interleave as        (b ': bs) (b ': cs)
deriving instance Show (Interleave as bs cs)
type IsInterleave as bs = TyPred (Interleave as bs)
instance Auto (IsInterleave '[] '[]) '[] where
    auto = IntZ
instance Auto (IsInterleave as bs) cs => Auto (IsInterleave (a ': as) bs) (a ': cs) where
    auto = IntL (auto @_ @(IsInterleave as bs) @cs)
instance {-# INCOHERENT #-} Auto (IsInterleave as bs) cs => Auto (IsInterleave as (b ': bs)) (b ': cs) where
    auto = IntR (auto @_ @(IsInterleave as bs) @cs)
instance (SDecide k, SingI (as :: [k]), SingI bs) => Decidable (IsInterleave as bs) where
    decide = case sing @as of
      SNil -> case sing @bs of
        SNil -> \case
          SNil -> Proved IntZ
          _ `SCons` _ -> Disproved $ \case {}
        y `SCons` (Sing :: Sing bs') -> \case
          z `SCons` (zs :: Sing cs') -> case y %~ z of
            Proved Refl -> case decide @(IsInterleave '[] bs') zs of
              Proved i -> Proved $ IntR i
              Disproved v -> Disproved $ \case
                IntR i -> v i
            Disproved v -> Disproved $ \case
              IntR _ -> v Refl
          SNil -> Disproved $ \case {}
      x `SCons` (Sing :: Sing as') -> case sing @bs of
        SNil -> \case
          z `SCons` (zs :: Sing cs') -> case x %~ z of
            Proved Refl -> case decide @(IsInterleave as' '[]) zs of
              Proved i -> Proved $ IntL i
              Disproved v -> Disproved $ \case
                IntL i -> v i
            Disproved v -> Disproved $ \case
              IntL _ -> v Refl
          SNil -> Disproved $ \case {}
        y `SCons` (Sing :: Sing bs') -> \case
          SNil -> Disproved $ \case {}
          z `SCons` (zs :: Sing cs') -> case x %~ z of
            Proved Refl -> case decide @(IsInterleave as' bs) zs of
              Proved i    -> Proved $ IntL i
              Disproved v -> case y %~ z of
                Proved Refl -> case decide @(IsInterleave as bs') zs of
                  Proved i -> Proved $ IntR i
                  Disproved u -> Disproved $ \case
                    IntL i -> v i
                    IntR i -> u i
                Disproved u -> Disproved $ \case
                  IntL i -> v i
                  IntR _ -> u Refl
            Disproved v -> case y %~ z of
              Proved Refl -> case decide @(IsInterleave as bs') zs of
                Proved i -> Proved $ IntR i
                Disproved u -> Disproved $ \case
                  IntL _ -> v Refl
                  IntR i -> u i
              Disproved u -> Disproved $ \case
                IntL _ -> v Refl
                IntR _ -> u Refl
autoInterleave :: forall as bs cs. Auto (IsInterleave as bs) cs => Interleave as bs cs
autoInterleave = auto @_ @(IsInterleave as bs) @cs
interleaveRec :: Interleave as bs cs -> Rec f as -> Rec f bs -> Rec f cs
interleaveRec = \case
    IntZ -> \case
      RNil -> \case
        RNil -> RNil
    IntL m -> \case
      x :& xs -> \ys -> x :& interleaveRec m xs ys
    IntR m -> \xs -> \case
      y :& ys -> y :& interleaveRec m xs ys
unweaveRec :: Interleave as bs cs -> Rec f cs -> (Rec f as, Rec f bs)
unweaveRec = \case
    IntZ -> \case
      RNil -> (RNil, RNil)
    IntL m -> \case
      x :& xs -> first  (x :&) . unweaveRec m $ xs
    IntR m -> \case
      x :& xs -> second (x :&) . unweaveRec m $ xs
interleavedIxes :: Interleave as bs cs -> Rec (Index as :+: Index bs) cs
interleavedIxes = \case
    IntZ   -> RNil
    IntL i -> L1 IZ :& VR.rmap (\case L1 i' -> L1 (IS i'); R1 j -> R1 j)
                               (interleavedIxes i)
    IntR j -> R1 IZ :& VR.rmap (\case L1 i -> L1 i; R1 j' -> R1 (IS j'))
                               (interleavedIxes j)
injectIndexL :: Interleave as bs cs -> Index as a -> Index cs a
injectIndexL = \case
    IntZ -> \case {}
    IntL m -> \case
      IZ -> IZ
      IS i -> IS (injectIndexL m i)
    IntR m -> IS . injectIndexL m
injectIndexR :: Interleave as bs cs -> Index bs b -> Index cs b
injectIndexR = \case
    IntZ -> \case {}
    IntL m -> IS . injectIndexR m
    IntR m -> \case
      IZ -> IZ
      IS i -> IS (injectIndexR m i)
unweaveIndex :: Interleave as bs cs -> Index cs c -> Either (Index as c) (Index bs c)
unweaveIndex = \case
    IntZ -> \case {}
    IntL m -> \case
      IZ   -> Left IZ
      IS i -> first IS $ unweaveIndex m i
    IntR m -> \case
      IZ   -> Right IZ
      IS i -> second IS $ unweaveIndex m i
interleaveRecIso
    :: (Profunctor p, Functor f)
    => Interleave as bs cs
    -> p (Rec g as, Rec g bs) (f (Rec g as, Rec g bs))
    -> p (Rec g cs)           (f (Rec g cs))
interleaveRecIso m = dimap (unweaveRec m) ((fmap . uncurry) (interleaveRec m))
swapInterleave
    :: Interleave as bs cs
    -> Interleave bs as cs
swapInterleave = \case
    IntZ   -> IntZ
    IntL i -> IntR $ swapInterleave i
    IntR i -> IntL $ swapInterleave i
interleaveShapes
    :: Interleave as bs cs
    -> (Shape [] as, Shape [] bs, Shape [] cs)
interleaveShapes = \case
    IntZ   -> (RNil, RNil, RNil)
    IntL i ->
      let (as         , bs         , cs         ) = interleaveShapes i
      in  (Proxy :& as, bs         , Proxy :& cs)
    IntR i ->
      let (as         , bs         , cs         ) = interleaveShapes i
      in  (as         , Proxy :& bs, Proxy :& cs)
data Subset :: [k] -> [k] -> Type where
    SubsetNil :: Subset '[] '[]
    SubsetNo  :: Subset as bs -> Subset as        (b ': bs)
    SubsetYes :: Subset as bs -> Subset (a ': as) (a ': bs)
interleaveLToSubset :: Interleave as bs cs -> Subset as cs
interleaveLToSubset = \case
    IntZ   -> SubsetNil
    IntL i -> SubsetYes . interleaveLToSubset $ i
    IntR i -> SubsetNo  . interleaveLToSubset $ i
interleaveRToSubset :: Interleave as bs cs -> Subset bs cs
interleaveRToSubset = \case
    IntZ   -> SubsetNil
    IntL i -> SubsetNo  . interleaveRToSubset $ i
    IntR i -> SubsetYes . interleaveRToSubset $ i
subsetToInterleaveL
    :: Subset as cs
    -> (forall bs. Interleave as bs cs -> r)
    -> r
subsetToInterleaveL = \case
    SubsetNil   -> \f -> f IntZ
    SubsetNo  s -> \f -> subsetToInterleaveL s (f . IntR)
    SubsetYes s -> \f -> subsetToInterleaveL s (f . IntL)
subsetToInterleaveR
    :: Subset bs cs
    -> (forall as. Interleave as bs cs -> r)
    -> r
subsetToInterleaveR = \case
    SubsetNil   -> \f -> f IntZ
    SubsetNo  s -> \f -> subsetToInterleaveR s (f . IntL)
    SubsetYes s -> \f -> subsetToInterleaveR s (f . IntR)
subsetComplement
    :: Subset as cs
    -> (forall bs. Subset bs cs -> r)
    -> r
subsetComplement = \case
    SubsetNil   -> \f -> f SubsetNil
    SubsetNo  s -> \f -> subsetComplement s (f . SubsetYes)
    SubsetYes s -> \f -> subsetComplement s (f . SubsetNo)
deriving instance Show (Subset as bs)
type IsSubset as = TyPred (Subset as)
instance Auto (IsSubset '[]) '[] where
    auto = SubsetNil
instance {-# OVERLAPPING #-} Auto (IsSubset as) bs => Auto (IsSubset as) (b ': bs) where
    auto = SubsetNo (auto @_ @(IsSubset as) @bs)
instance {-# OVERLAPPING #-} Auto (IsSubset as) bs => Auto (IsSubset (a ': as)) (a ': bs) where
    auto = SubsetYes (auto @_ @(IsSubset as) @bs)
instance (SDecide k, SingI (as :: [k])) => Decidable (IsSubset as) where
    decide = case sing @as of
      SNil -> \case
        SNil -> Proved SubsetNil
        _ `SCons` ys -> case decide @(IsSubset '[]) ys of
          Proved s    -> Proved $ SubsetNo s
          Disproved v -> Disproved $ \case
            SubsetNo s -> v s
      x `SCons` (Sing :: Sing as') -> \case
        SNil -> Disproved $ \case {}
        y `SCons` ys -> case x %~ y of
          Proved Refl -> case decide @(IsSubset as') ys of
            Proved s    -> Proved $ SubsetYes s
            Disproved v -> case decide @(IsSubset as) ys of
              Proved s    -> Proved $ SubsetNo s
              Disproved u -> Disproved $ \case
                SubsetNo s  -> u s
                SubsetYes s -> v s
          Disproved v -> case decide @(IsSubset as) ys of
            Proved s    -> Proved $ SubsetNo s
            Disproved u -> Disproved $ \case
              SubsetNo s  -> u s
              SubsetYes _ -> v Refl
autoSubset :: forall as bs. Auto (IsSubset as) bs => Subset as bs
autoSubset = auto @_ @(IsSubset as) @bs
subsetRec :: Subset as bs -> Lens' (Rec f bs) (Rec f as)
subsetRec = \case
    SubsetNil   -> id
    SubsetNo  s -> \f -> \case
      x :& xs -> (x :&) <$> subsetRec s f xs
    SubsetYes s -> \f -> \case
      x :& xs -> fmap (uncurry (:&))
               . getCompose
               . subsetRec s (Compose . fmap (\(y :& ys) -> (y,ys)) . f . (x :&))
               $ xs
getSubset
    :: Subset as bs
    -> Rec f bs
    -> Rec f as
getSubset = view . subsetRec
subsetIxes
    :: Subset as bs
    -> Rec (Index bs) as
subsetIxes s = getSubset s . imapProd const $ sp
  where
    (_, sp) = subsetShapes s
subsetShapes
    :: Subset as bs
    -> (Shape [] as, Shape [] bs)
subsetShapes = \case
    SubsetNil    -> (RNil, RNil)
    SubsetNo   s -> second (Proxy :&) $ subsetShapes s
    SubsetYes  s -> bimap (Proxy :&) (Proxy :&) $ subsetShapes s
weakenSubsetIndex
    :: Subset as bs
    -> Index as a
    -> Index bs a
weakenSubsetIndex = \case
    SubsetNil   -> \case {}
    SubsetNo  s -> IS . weakenSubsetIndex s
    SubsetYes s -> \case
      IZ   -> IZ
      IS i -> IS $ weakenSubsetIndex s i
strengthenSubsetIndex
    :: Subset as bs
    -> Index bs a
    -> Maybe (Index as a)
strengthenSubsetIndex = \case
    SubsetNil   -> \case {}
    SubsetNo  s -> \case
      IZ   -> Nothing
      IS i -> strengthenSubsetIndex s i
    SubsetYes s -> \case
      IZ   -> Just IZ
      IS i -> IS <$> strengthenSubsetIndex s i