{-# 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