list-witnesses 0.1.4.0 → 0.1.4.1
raw patch · 4 files changed
+833/−704 lines, 4 filesdep ~decidabledep ~functor-productsdep ~microlensPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: decidable, functor-products, microlens, profunctors, singletons, singletons-base, vinyl
API changes (from Hackage documentation)
- Data.Type.List.Edit: [DelS] :: Delete as bs x -> Delete (a : as) (a : bs) x
+ Data.Type.List.Edit: [DelS] :: Delete as bs x -> Delete (a ': as) (a ': bs) x
- Data.Type.List.Edit: [DelZ] :: Delete (x : as) as x
+ Data.Type.List.Edit: [DelZ] :: Delete (x ': as) as x
- Data.Type.List.Edit: [InsS] :: Insert as bs x -> Insert (a : as) (a : bs) x
+ Data.Type.List.Edit: [InsS] :: Insert as bs x -> Insert (a ': as) (a ': bs) x
- Data.Type.List.Edit: [InsZ] :: Insert as (x : as) x
+ Data.Type.List.Edit: [InsZ] :: Insert as (x ': as) x
- Data.Type.List.Edit: [SDelS] :: SDelete as bs x del -> SDelete (a : as) (a : bs) x ('DelS del)
+ Data.Type.List.Edit: [SDelS] :: SDelete as bs x del -> SDelete (a ': as) (a ': bs) x ('DelS del)
- Data.Type.List.Edit: [SDelZ] :: SDelete (x : as) as x 'DelZ
+ Data.Type.List.Edit: [SDelZ] :: SDelete (x ': as) as x 'DelZ
- Data.Type.List.Edit: [SInsS] :: SInsert as bs x ins -> SInsert (a : as) (a : bs) x ('InsS ins)
+ Data.Type.List.Edit: [SInsS] :: SInsert as bs x ins -> SInsert (a ': as) (a ': bs) x ('InsS ins)
- Data.Type.List.Edit: [SInsZ] :: SInsert as (x : as) x 'InsZ
+ Data.Type.List.Edit: [SInsZ] :: SInsert as (x ': as) x 'InsZ
- Data.Type.List.Edit: [SSubS] :: SSubstitute as bs x y sub -> SSubstitute (c : as) (c : bs) x y ('SubS sub)
+ Data.Type.List.Edit: [SSubS] :: SSubstitute as bs x y sub -> SSubstitute (c ': as) (c ': bs) x y ('SubS sub)
- Data.Type.List.Edit: [SSubZ] :: SSubstitute (x : as) (y : as) x y 'SubZ
+ Data.Type.List.Edit: [SSubZ] :: SSubstitute (x ': as) (y ': as) x y 'SubZ
- Data.Type.List.Edit: [SubS] :: Substitute as bs x y -> Substitute (c : as) (c : bs) x y
+ Data.Type.List.Edit: [SubS] :: Substitute as bs x y -> Substitute (c ': as) (c ': bs) x y
- Data.Type.List.Edit: [SubZ] :: Substitute (x : as) (y : as) x y
+ Data.Type.List.Edit: [SubZ] :: Substitute (x ': as) (y ': as) x y
- Data.Type.List.Sublist: [AppS] :: Append as bs cs -> Append (a : as) bs (a : cs)
+ Data.Type.List.Sublist: [AppS] :: Append as bs cs -> Append (a ': as) bs (a ': cs)
- Data.Type.List.Sublist: [IntL] :: Interleave as bs cs -> Interleave (a : as) bs (a : cs)
+ Data.Type.List.Sublist: [IntL] :: Interleave as bs cs -> Interleave (a ': as) bs (a ': cs)
- Data.Type.List.Sublist: [IntR] :: Interleave as bs cs -> Interleave as (b : bs) (b : cs)
+ Data.Type.List.Sublist: [IntR] :: Interleave as bs cs -> Interleave as (b ': bs) (b ': cs)
- Data.Type.List.Sublist: [PreS] :: Prefix as bs -> Prefix (a : as) (a : bs)
+ Data.Type.List.Sublist: [PreS] :: Prefix as bs -> Prefix (a ': as) (a ': bs)
- Data.Type.List.Sublist: [SubsetNo] :: Subset as bs -> Subset as (b : bs)
+ Data.Type.List.Sublist: [SubsetNo] :: Subset as bs -> Subset as (b ': bs)
- Data.Type.List.Sublist: [SubsetYes] :: Subset as bs -> Subset (a : as) (a : bs)
+ Data.Type.List.Sublist: [SubsetYes] :: Subset as bs -> Subset (a ': as) (a ': bs)
- Data.Type.List.Sublist: [SufS] :: Suffix as bs -> Suffix as (b : bs)
+ Data.Type.List.Sublist: [SufS] :: Suffix as bs -> Suffix as (b ': bs)
Files
- CHANGELOG.md +9/−0
- list-witnesses.cabal +8/−8
- src/Data/Type/List/Edit.hs +332/−276
- src/Data/Type/List/Sublist.hs +484/−420
CHANGELOG.md view
@@ -1,6 +1,15 @@ Changelog ========= +Version 0.1.4.1+---------------++*February 27, 2023*++<https://github.com/mstksg/list-witnesses/releases/tag/v0.1.4.1>++* Remove upper bounds, fix deprecated pragmas+ Version 0.1.4.0 ---------------
list-witnesses.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: list-witnesses-version: 0.1.4.0+version: 0.1.4.1 synopsis: Witnesses for working with type-level lists description: Collection of assorted inductive witnesses and functions for working with type-level lists.@@ -44,11 +44,11 @@ ghc-options: -Wall -Wcompat -Wredundant-constraints -Werror=incomplete-patterns build-depends: base >=4.7 && <5- , decidable >=0.3.1 && <0.4- , functor-products >=0.1.2 && <0.2- , microlens <0.5- , profunctors <5.7- , singletons-base >=3.0 && <3.1- , singletons >=3.0 && <3.2- , vinyl >=0.14.3 && <0.15+ , decidable >=0.3.1.1+ , functor-products >=0.1.2+ , microlens+ , profunctors+ , singletons-base >=3.0+ , singletons >=3.0+ , vinyl >=0.14.3 default-language: Haskell2010
src/Data/Type/List/Edit.hs view
@@ -1,19 +1,18 @@-{-# LANGUAGE EmptyCase #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE EmptyCase #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeInType #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-} -- | -- Module : Data.Type.List.Edit@@ -27,59 +26,88 @@ -- Witnesses regarding single-item edits of lists. module Data.Type.List.Edit ( -- * Simple edits- Insert(..), autoInsert- , Delete(..), autoDelete- , insToDel- , delToIns- , Substitute(..), autoSubstitute- , flipSub- , subToDelIns+ Insert (..),+ autoInsert,+ Delete (..),+ autoDelete,+ insToDel,+ delToIns,+ Substitute (..),+ autoSubstitute,+ flipSub,+ subToDelIns,+ -- ** Predicates- , IsInsert, InsertedInto- , IsDelete, DeletedFrom- , IsSubstitute+ IsInsert,+ InsertedInto,+ IsDelete,+ DeletedFrom,+ IsSubstitute,+ -- ** Singletons- , SInsert(..)- , SDelete(..)- , SSubstitute(..)+ SInsert (..),+ SDelete (..),+ SSubstitute (..),+ -- * Compound edits- , Edit(..)- , compEdit- , flipEdit+ Edit (..),+ compEdit,+ flipEdit,+ -- * Rec- , insertRec, deleteRec, deleteGetRec- , recLens, substituteRec+ insertRec,+ deleteRec,+ deleteGetRec,+ recLens,+ substituteRec,+ -- * Index+ -- ** Manipulating indices- , insertIndex- , DeletedIx(..), deleteIndex, deleteIndex_- , SubstitutedIx(..), substituteIndex, substituteIndex_+ insertIndex,+ DeletedIx (..),+ deleteIndex,+ deleteIndex_,+ SubstitutedIx (..),+ substituteIndex,+ substituteIndex_,+ -- ** Converting from indices- , withDelete, withInsert, withInsertAfter+ withDelete,+ withInsert,+ withInsertAfter,+ -- * Type-Level- , InsertIndex, sInsertIndex- , SDeletedIx(..)- , DeleteIndex, sDeleteIndex- , SSubstitutedIx(..)- , SubstituteIndex, sSubstituteIndex+ InsertIndex,+ sInsertIndex,+ SDeletedIx (..),+ DeleteIndex,+ sDeleteIndex,+ SSubstitutedIx (..),+ SubstituteIndex,+ sSubstituteIndex,+ -- ** Defunctionalization Symbols- , InsertIndexSym0, InsertIndexSym- , DeleteIndexSym0, DeleteIndexSym- , SubstituteIndexSym0, SubstituteIndexSym- ) where+ InsertIndexSym0,+ InsertIndexSym,+ DeleteIndexSym0,+ DeleteIndexSym,+ SubstituteIndexSym0,+ SubstituteIndexSym,+) where -import Data.Function.Singletons (IdSym0)-import Data.Kind-import Data.List.Singletons (SList(..))-import Data.Singletons-import Data.Singletons.Decide-import Data.Singletons.Sigma-import Data.Type.Functor.Product-import Data.Type.Predicate-import Data.Type.Predicate.Auto-import Data.Type.Predicate.Param-import Lens.Micro hiding ((%~))-import qualified Control.Category as C+import qualified Control.Category as C+import Data.Function.Singletons (IdSym0)+import Data.Kind+import Data.List.Singletons (SList (..))+import Data.Singletons+import Data.Singletons.Decide+import Data.Singletons.Sigma+import Data.Type.Functor.Product+import Data.Type.Predicate+import Data.Type.Predicate.Auto+import Data.Type.Predicate.Param+import Lens.Micro hiding ((%~)) -- | An @'Insert' as bs x@ is a witness that you can insert @x@ into some -- position in list @as@ to produce list @bs@. It is essentially 'Delete'@@ -96,8 +124,8 @@ -- -- @bs@ will always be exactly one item longer than @as@. data Insert :: [k] -> [k] -> k -> Type where- InsZ :: Insert as (x ': as) x- InsS :: Insert as bs x -> Insert (a ': as) (a ': bs) x+ InsZ :: Insert as (x ': as) x+ InsS :: Insert as bs x -> Insert (a ': as) (a ': bs) x deriving instance Show (Insert as bs x) @@ -109,29 +137,17 @@ -- | Prefers the "earlier" insert if there is ambiguity instance Auto (IsInsert as (x ': as)) x where- auto = InsZ+ auto = InsZ instance {-# INCOHERENT #-} Auto (IsInsert as bs) x => Auto (IsInsert (a ': as) (a ': bs)) x where- auto = InsS (auto @_ @(IsInsert as bs) @x)+ auto = InsS (auto @_ @(IsInsert as bs) @x) instance (SDecide k, SingI (as :: [k]), SingI bs) => Decidable (IsInsert as bs) where- decide z = case sing @bs of- SNil -> Disproved $ \case {}- y `SCons` (ys@Sing :: Sing bs') -> case y %~ z of- Proved Refl -> case sing @as %~ ys of- Proved Refl -> Proved InsZ- Disproved v -> case sing @as of- SNil -> Disproved $ \case- InsZ -> v Refl- x `SCons` (Sing :: Sing as') -> case x %~ y of- Proved Refl -> case decide @(IsInsert as' bs') z of- Proved i -> Proved $ InsS i- Disproved u -> Disproved $ \case- InsZ -> u InsZ- InsS i -> u i- Disproved u -> Disproved $ \case- InsZ -> v Refl- InsS _ -> u Refl+ decide z = case sing @bs of+ SNil -> Disproved $ \case {}+ y `SCons` (ys@Sing :: Sing bs') -> case y %~ z of+ Proved Refl -> case sing @as %~ ys of+ Proved Refl -> Proved InsZ Disproved v -> case sing @as of SNil -> Disproved $ \case InsZ -> v Refl@@ -142,8 +158,20 @@ InsZ -> u InsZ InsS i -> u i Disproved u -> Disproved $ \case- InsZ -> v Refl+ InsZ -> v Refl InsS _ -> u Refl+ Disproved v -> case sing @as of+ SNil -> Disproved $ \case+ InsZ -> v Refl+ x `SCons` (Sing :: Sing as') -> case x %~ y of+ Proved Refl -> case decide @(IsInsert as' bs') z of+ Proved i -> Proved $ InsS i+ Disproved u -> Disproved $ \case+ InsZ -> u InsZ+ InsS i -> u i+ Disproved u -> Disproved $ \case+ InsZ -> v Refl+ InsS _ -> u Refl -- | If @bs@ satisfies @'InsertedInto' as@, it means that there exists some -- element @x@ such that @'IsInsert' as bs \@\@ x@: you can get @bs@ by@@ -166,22 +194,22 @@ type InsertedInto (as :: [k]) = (TyPP (Insert as) :: ParamPred [k] k) instance (SDecide k, SingI (as :: [k])) => Decidable (Found (InsertedInto as)) where- decide = \case- SNil -> Disproved $ \(_ :&: i) -> case i of {}- y `SCons` ys -> case sing @as %~ ys of- Proved Refl -> Proved $ y :&: InsZ- Disproved v -> case sing @as of- SNil -> Disproved $ \(_ :&: i) -> case i of+ decide = \case+ SNil -> Disproved $ \(_ :&: i) -> case i of {}+ y `SCons` ys -> case sing @as %~ ys of+ Proved Refl -> Proved $ y :&: InsZ+ Disproved v -> case sing @as of+ SNil -> Disproved $ \(_ :&: i) -> case i of+ InsZ -> v Refl+ x `SCons` (Sing :: Sing as') -> case x %~ y of+ Proved Refl -> case decide @(Found (InsertedInto as')) ys of+ Proved (z :&: i) -> Proved $ z :&: InsS i+ Disproved u -> Disproved $ \(z :&: i) -> case i of+ InsZ -> u $ z :&: InsZ+ InsS i' -> u $ z :&: i'+ Disproved u -> Disproved $ \(_ :&: i) -> case i of InsZ -> v Refl- x `SCons` (Sing :: Sing as') -> case x %~ y of- Proved Refl -> case decide @(Found (InsertedInto as')) ys of- Proved (z :&: i) -> Proved $ z :&: InsS i- Disproved u -> Disproved $ \(z :&: i) -> case i of- InsZ -> u $ z :&: InsZ- InsS i' -> u $ z :&: i'- Disproved u -> Disproved $ \(_ :&: i) -> case i of- InsZ -> v Refl- InsS _ -> u Refl+ InsS _ -> u Refl -- | Automatically generate an 'Insert' if @as@, @bs@ and @x@ are known -- statically.@@ -200,16 +228,16 @@ -- | Kind-indexed singleton for 'Insert'. data SInsert (as :: [k]) (bs :: [k]) (x :: k) :: Insert as bs x -> Type where- SInsZ :: SInsert as (x ': as) x 'InsZ- SInsS :: SInsert as bs x ins -> SInsert (a ': as) (a ': bs) x ('InsS ins)+ SInsZ :: SInsert as (x ': as) x 'InsZ+ SInsS :: SInsert as bs x ins -> SInsert (a ': as) (a ': bs) x ('InsS ins) deriving instance Show (SInsert as bs x del) -- | Flip an insertion. insToDel :: Insert as bs x -> Delete bs as x insToDel = \case- InsZ -> DelZ- InsS i -> DelS (insToDel i)+ InsZ -> DelZ+ InsS i -> DelS (insToDel i) -- | A @'Delete' as bs x@ is a witness that you can delete item @x@ from -- @as@ to produce the list @bs@. It is essentially 'Insert' flipped.@@ -224,8 +252,8 @@ -- -- @bs@ will always be exactly one item shorter than @as@. data Delete :: [k] -> [k] -> k -> Type where- DelZ :: Delete (x ': as) as x- DelS :: Delete as bs x -> Delete (a ': as) (a ': bs) x+ DelZ :: Delete (x ': as) as x+ DelS :: Delete as bs x -> Delete (a ': as) (a ': bs) x deriving instance Show (Delete as bs x) @@ -237,13 +265,13 @@ -- | Prefers the "earlier" delete if there is ambiguity instance Auto (IsDelete (x ': as) as) x where- auto = DelZ+ auto = DelZ instance {-# INCOHERENT #-} Auto (IsDelete as bs) x => Auto (IsDelete (a ': as) (a ': bs)) x where- auto = DelS (auto @_ @(IsDelete as bs) @x)+ auto = DelS (auto @_ @(IsDelete as bs) @x) instance (SDecide k, SingI (as :: [k]), SingI bs) => Decidable (IsDelete as bs) where- decide = mapDecision insToDel delToIns . decide @(IsInsert bs as)+ decide = mapDecision insToDel delToIns . decide @(IsInsert bs as) -- | If @bs@ satisfies @'DeletedFrom' as@, it means that there exists some -- element @x@ such that @'IsDelete' as bs \@\@ x@: you can get @bs@ by@@ -266,9 +294,10 @@ type DeletedFrom (as :: [k]) = (TyPP (Delete as) :: ParamPred [k] k) instance (SDecide k, SingI (as :: [k])) => Decidable (Found (DeletedFrom as)) where- decide (Sing :: Sing bs) =- mapDecision (mapSigma (sing @IdSym0) insToDel)- (mapSigma (sing @IdSym0) delToIns)+ decide (Sing :: Sing bs) =+ mapDecision+ (mapSigma (sing @IdSym0) insToDel)+ (mapSigma (sing @IdSym0) delToIns) $ decide @(Found (InsertedInto bs)) (sing @as) -- | Automatically generate an 'Delete' if @as@, @bs@ and @x@ are known@@ -288,16 +317,16 @@ -- | Kind-indexed singleton for 'Delete'. data SDelete (as :: [k]) (bs :: [k]) (x :: k) :: Delete as bs x -> Type where- SDelZ :: SDelete (x ': as) as x 'DelZ- SDelS :: SDelete as bs x del -> SDelete (a ': as) (a ': bs) x ('DelS del)+ SDelZ :: SDelete (x ': as) as x 'DelZ+ SDelS :: SDelete as bs x del -> SDelete (a ': as) (a ': bs) x ('DelS del) deriving instance Show (SDelete as bs x del) -- | Flip a deletion. delToIns :: Delete as bs x -> Insert bs as x delToIns = \case- DelZ -> InsZ- DelS d -> InsS (delToIns d)+ DelZ -> InsZ+ DelS d -> InsS (delToIns d) -- | A @'Substitute' as bs x y@ is a witness that you can replace item @x@ in -- @as@ with item @y@ to produce @bs@.@@ -309,10 +338,9 @@ -- SubS SubZ :: Substitute '[1,2,3] '[1,4,3] 2 4 -- SubS (SubS SubZ) :: Substitute '[1,2,3] '[1,2,4] 3 4 -- @--- data Substitute :: [k] -> [k] -> k -> k -> Type where- SubZ :: Substitute (x ': as) (y ': as) x y- SubS :: Substitute as bs x y -> Substitute (c ': as) (c ': bs) x y+ SubZ :: Substitute (x ': as) (y ': as) x y+ SubS :: Substitute as bs x y -> Substitute (c ': as) (c ': bs) x y deriving instance Show (Substitute as bs x y) @@ -323,14 +351,14 @@ type IsSubstitute as bs x = TyPred (Substitute as bs x) instance Auto (IsSubstitute (x ': as) (y ': as) x) y where- auto = SubZ+ auto = SubZ -- | Prefers the earlier subsitution if there is ambiguity. instance Auto (IsSubstitute as bs x) y => Auto (IsSubstitute (c ': as) (c ': bs) x) y where- auto = SubS (auto @_ @(IsSubstitute as bs x) @y)+ auto = SubS (auto @_ @(IsSubstitute as bs x) @y) instance {-# INCOHERENT #-} Auto (IsSubstitute (x ': as) (x ': as) x) x where- auto = SubZ+ auto = SubZ -- | Automatically generate an 'Substitute' if @as@, @bs@, @x@, and @y@ are -- known statically.@@ -349,24 +377,25 @@ -- | Kind-indexed singleton for 'Substitute'. data SSubstitute (as :: [k]) (bs :: [k]) (x :: k) (y :: k) :: Substitute as bs x y -> Type where- SSubZ :: SSubstitute (x ': as) (y ': as) x y 'SubZ- SSubS :: SSubstitute as bs x y sub- -> SSubstitute (c ': as) (c ': bs) x y ('SubS sub)+ SSubZ :: SSubstitute (x ': as) (y ': as) x y 'SubZ+ SSubS ::+ SSubstitute as bs x y sub ->+ SSubstitute (c ': as) (c ': bs) x y ('SubS sub) -- | Flip a substitution flipSub :: Substitute as bs x y -> Substitute bs as y x flipSub = \case- SubZ -> SubZ- SubS s -> SubS (flipSub s)+ SubZ -> SubZ+ SubS s -> SubS (flipSub s) -- | Decompose a 'Substitute' into a 'Delete' followed by an 'Insert'.-subToDelIns- :: Substitute as bs x y- -> (forall cs. Delete as cs x -> Insert cs bs y -> r)- -> r+subToDelIns ::+ Substitute as bs x y ->+ (forall cs. Delete as cs x -> Insert cs bs y -> r) ->+ r subToDelIns = \case- SubZ -> \f -> f DelZ InsZ- SubS s -> \f -> subToDelIns s $ \d i -> f (DelS d) (InsS i)+ SubZ -> \f -> f DelZ InsZ+ SubS s -> \f -> subToDelIns s $ \d i -> f (DelS d) (InsS i) -- | An @'Edit' as bs@ is a reversible edit script transforming @as@ into -- @bs@ through successive insertions, deletions, and substitutions.@@ -374,25 +403,25 @@ -- TODO: implement Wagner-Fischer or something similar to minimize find -- a minimal edit distance data Edit :: [k] -> [k] -> Type where- ENil :: Edit as as- EIns :: Insert bs cs x -> Edit as bs -> Edit as cs- EDel :: Delete bs cs x -> Edit as bs -> Edit as cs- ESub :: Substitute bs cs x y -> Edit as bs -> Edit as cs+ ENil :: Edit as as+ EIns :: Insert bs cs x -> Edit as bs -> Edit as cs+ EDel :: Delete bs cs x -> Edit as bs -> Edit as cs+ ESub :: Substitute bs cs x y -> Edit as bs -> Edit as cs deriving instance Show (Edit as bs) -- | Compose two 'Edit's compEdit :: Edit as bs -> Edit bs cs -> Edit as cs compEdit xs = \case- ENil -> xs- EIns i ys -> EIns i (compEdit xs ys)- EDel d ys -> EDel d (compEdit xs ys)- ESub s ys -> ESub s (compEdit xs ys)+ ENil -> xs+ EIns i ys -> EIns i (compEdit xs ys)+ EDel d ys -> EDel d (compEdit xs ys)+ ESub s ys -> ESub s (compEdit xs ys) -- | 'Edit' composition instance C.Category Edit where- id = ENil- xs . ys = compEdit ys xs+ id = ENil+ xs . ys = compEdit ys xs -- | Reverse an 'Edit' script. O(n^2). Please do not use ever in any -- circumstance.@@ -400,34 +429,35 @@ -- TODO: Make O(n) using diff lists. flipEdit :: Edit as bs -> Edit bs as flipEdit = \case- ENil -> ENil- EIns i ys -> EDel (insToDel i) ENil `compEdit` flipEdit ys- EDel d ys -> EIns (delToIns d) ENil `compEdit` flipEdit ys- ESub s ys -> ESub (flipSub s) ENil `compEdit` flipEdit ys+ ENil -> ENil+ EIns i ys -> EDel (insToDel i) ENil `compEdit` flipEdit ys+ EDel d ys -> EIns (delToIns d) ENil `compEdit` flipEdit ys+ ESub s ys -> ESub (flipSub s) ENil `compEdit` flipEdit ys -- | Insert a value into a 'Rec', at a position indicated by the 'Insert'. insertRec :: Insert as bs x -> f x -> Rec f as -> Rec f bs insertRec = \case- InsZ -> (:&)- InsS i -> \x -> \case- y :& ys -> y :& insertRec i x ys+ InsZ -> (:&)+ InsS i -> \x -> \case+ y :& ys -> y :& insertRec i x ys -- | Retrieve and delete a value in a 'Rec', at a position indicated by the 'Delete'. deleteGetRec :: Delete as bs x -> Rec f as -> (f x, Rec f bs) deleteGetRec = \case- DelZ -> \case- x :& xs -> (x, xs)- DelS d -> \case- x :& xs -> let (y, ys) = deleteGetRec d xs- in (y, x :& ys)+ DelZ -> \case+ x :& xs -> (x, xs)+ DelS d -> \case+ x :& xs ->+ let (y, ys) = deleteGetRec d xs+ in (y, x :& ys) -- | Delete a value in a 'Rec', at a position indicated by the 'Delete'. deleteRec :: Delete as bs x -> Rec f as -> Rec f bs deleteRec = \case- DelZ -> \case- _ :& xs -> xs- DelS d -> \case- x :& xs -> x :& deleteRec d xs+ DelZ -> \case+ _ :& xs -> xs+ DelS d -> \case+ x :& xs -> x :& deleteRec d xs -- | A type-changing lens into a value in a 'Rec', given a 'Substitute' -- indicating which value.@@ -445,15 +475,17 @@ -- -- This is similar to 'Data.Vinyl.Lens.rlensC' from /vinyl/, but is built -- explicitly and inductively, instead of using typeclass magic.-recLens- :: forall as bs x y f. ()- => Substitute as bs x y- -> Lens (Rec f as) (Rec f bs) (f x) (f y)+recLens ::+ forall as bs x y f.+ () =>+ Substitute as bs x y ->+ Lens (Rec f as) (Rec f bs) (f x) (f y) recLens s0 (f :: f x -> g (f y)) = go s0 where- go :: Substitute cs ds x y- -> Rec f cs- -> g (Rec f ds)+ go ::+ Substitute cs ds x y ->+ Rec f cs ->+ g (Rec f ds) go = \case SubZ -> \case x :& xs -> (:& xs) <$> f x@@ -462,11 +494,11 @@ -- | Substitute a value in a 'Rec' at a given position, indicated by the -- 'Substitute'. This is essentially a specialized version of 'recLens'.-substituteRec- :: Substitute as bs x y- -> (f x -> f y)- -> Rec f as- -> Rec f bs+substituteRec ::+ Substitute as bs x y ->+ (f x -> f y) ->+ Rec f as ->+ Rec f bs substituteRec s = over (recLens s) -- | If you add an item to @as@ to create @bs@, you also need to shift an@@ -475,17 +507,17 @@ -- same original value. insertIndex :: Insert as bs x -> Index as y -> Index bs y insertIndex = \case- InsZ -> IS- InsS ins -> \case- IZ -> IZ- IS i -> IS (insertIndex ins i)+ InsZ -> IS+ InsS ins -> \case+ IZ -> IZ+ IS i -> IS (insertIndex ins i) -- | Used as the return type of 'deleteIndex'. An @'DeletedIx' bs x y@ is -- like a @'Maybe' ('Index' bs y)@, except the 'Nothing' case witnesses -- that @x ~ y@. data DeletedIx :: [k] -> k -> k -> Type where- GotDeleted :: DeletedIx bs x x- NotDeleted :: Index bs y -> DeletedIx bs x y+ GotDeleted :: DeletedIx bs x x+ NotDeleted :: Index bs y -> DeletedIx bs x y deriving instance Show (DeletedIx bs x y) @@ -500,29 +532,29 @@ -- returns 'NotDeleted' with the unshifted index. deleteIndex :: Delete as bs x -> Index as y -> DeletedIx bs x y deleteIndex = \case- DelZ -> \case- IZ -> GotDeleted- IS i -> NotDeleted i- DelS del -> \case- IZ -> NotDeleted IZ- IS i -> case deleteIndex del i of- GotDeleted -> GotDeleted- NotDeleted j -> NotDeleted (IS j)+ DelZ -> \case+ IZ -> GotDeleted+ IS i -> NotDeleted i+ DelS del -> \case+ IZ -> NotDeleted IZ+ IS i -> case deleteIndex del i of+ GotDeleted -> GotDeleted+ NotDeleted j -> NotDeleted (IS j) -- | A version of 'deleteIndex' returning a simple 'Maybe'. This can be -- used if you don't care about witnessing that @x ~ y@ in the case that -- the index is the item that is deleted. deleteIndex_ :: Delete as bs x -> Index as y -> Maybe (Index bs y) deleteIndex_ del i = case deleteIndex del i of- GotDeleted -> Nothing- NotDeleted j -> Just j+ GotDeleted -> Nothing+ NotDeleted j -> Just j -- | Used as the return type of 'substituteIndex'. An @'SubstitutedIx' bs x y z@ is -- like an @'Either' ('Index' bs y) ('Index' bs z)@, except the 'Left' case -- witnesses that @x ~ z@. data SubstitutedIx :: [k] -> k -> k -> k -> Type where- GotSubbed :: Index bs y -> SubstitutedIx bs z y z- NotSubbed :: Index bs z -> SubstitutedIx bs x y z+ GotSubbed :: Index bs y -> SubstitutedIx bs z y z+ NotSubbed :: Index bs z -> SubstitutedIx bs x y z -- | If you substitute an item in @as@ to create @bs@, you also need to -- reshift @'Index' as z@ into @'Index' bs z@. This reshifts the 'Index'@@ -533,72 +565,75 @@ -- that the index was originally pointing to. If this is the case, this -- function returns 'GotSubbed', a witness that @x ~ z@. Otherwise, it -- returns 'NotSubbed'. Both contain the updated index.-substituteIndex- :: Substitute as bs x y- -> Index as z- -> SubstitutedIx bs x y z+substituteIndex ::+ Substitute as bs x y ->+ Index as z ->+ SubstitutedIx bs x y z substituteIndex = \case- SubZ -> \case- IZ -> GotSubbed IZ- IS i -> NotSubbed (IS i)- SubS s -> \case- IZ -> NotSubbed IZ- IS i -> case substituteIndex s i of- GotSubbed j -> GotSubbed (IS j)- NotSubbed j -> NotSubbed (IS j)+ SubZ -> \case+ IZ -> GotSubbed IZ+ IS i -> NotSubbed (IS i)+ SubS s -> \case+ IZ -> NotSubbed IZ+ IS i -> case substituteIndex s i of+ GotSubbed j -> GotSubbed (IS j)+ NotSubbed j -> NotSubbed (IS j) -- | A version of 'substituteIndex' returning a simple 'Either'. This can be -- the case if you don't care about witnessing @x ~ z@ in the case that the -- index is the item that was substituted.-substituteIndex_- :: Substitute as bs x y- -> Index as z- -> Either (Index bs y) (Index bs z)+substituteIndex_ ::+ Substitute as bs x y ->+ Index as z ->+ Either (Index bs y) (Index bs z) substituteIndex_ sub i = case substituteIndex sub i of- GotSubbed j -> Left j- NotSubbed j -> Right j+ GotSubbed j -> Left j+ NotSubbed j -> Right j -- | Given an 'Index' pointing to an element, create a 'Delete' -- corresponding to the given item. The type of the resulting list is -- existentially quantified, is guaranteed to be just exactly the original -- list minus the specified element.-withDelete- :: Index as x- -> (forall bs. Delete as bs x -> r)- -> r+withDelete ::+ Index as x ->+ (forall bs. Delete as bs x -> r) ->+ r withDelete = \case- IZ -> \f -> f DelZ- IS i -> \f -> withDelete i (f . DelS)+ IZ -> \f -> f DelZ+ IS i -> \f -> withDelete i (f . DelS) -- | Given an 'Index' pointing to an element, create an 'Insert' placing an -- item /directly before/ the given element. The type is existentailly -- quantified.-withInsert- :: Index as x- -> (forall bs. Insert as bs y -> r)- -> r+withInsert ::+ Index as x ->+ (forall bs. Insert as bs y -> r) ->+ r withInsert = \case- IZ -> \f -> f InsZ- IS i -> \f -> withInsert i (f . InsS)+ IZ -> \f -> f InsZ+ IS i -> \f -> withInsert i (f . InsS) -- | Given an 'Index' pointing to an element, create an 'Insert' placing an -- item /directly after/ the given element. The type is existentailly -- quantified.-withInsertAfter- :: Index as x- -> (forall bs. Insert as bs y -> r)- -> r+withInsertAfter ::+ Index as x ->+ (forall bs. Insert as bs y -> r) ->+ r withInsertAfter = \case- IZ -> \f -> f (InsS InsZ)- IS i -> \f -> withInsertAfter i (f . InsS)+ IZ -> \f -> f (InsS InsZ)+ IS i -> \f -> withInsertAfter i (f . InsS) -- | Type-level version of 'insertIndex'. Because of how GADTs and type -- families interact, the type-level lists and kinds of the insertion and -- index must be provided.-type family InsertIndex (as :: [k]) (bs :: [k]) (x :: k) (y :: k) (ins :: Insert as bs x) (i :: Index as y) :: Index bs y where- InsertIndex as (x ': as) x y 'InsZ i = 'IS i- InsertIndex (y ': as) (y ': bs) x y ('InsS ins) 'IZ = 'IZ- InsertIndex (a ': as) (a ': bs) x y ('InsS ins) ('IS i) = 'IS (InsertIndex as bs x y ins i)+type family+ InsertIndex (as :: [k]) (bs :: [k]) (x :: k) (y :: k) (ins :: Insert as bs x) (i :: Index as y) ::+ Index bs y+ where+ InsertIndex as (x ': as) x y 'InsZ i = 'IS i+ InsertIndex (y ': as) (y ': bs) x y ('InsS ins) 'IZ = 'IZ+ InsertIndex (a ': as) (a ': bs) x y ('InsS ins) ('IS i) = 'IS (InsertIndex as bs x y ins i) -- | Defunctionalization symbol for 'InsertIndex', expecting only the kind -- variables.@@ -612,30 +647,37 @@ type instance Apply (InsertIndexSym as bs x y ins) i = InsertIndex as bs x y ins i -- | Singleton witness for 'InsertIndex'.-sInsertIndex- :: SInsert as bs x ins- -> SIndex as y i- -> SIndex bs y (InsertIndex as bs x y ins i)+sInsertIndex ::+ SInsert as bs x ins ->+ SIndex as y i ->+ SIndex bs y (InsertIndex as bs x y ins i) sInsertIndex = \case- SInsZ -> SIS- SInsS ins -> \case- SIZ -> SIZ- SIS i -> SIS (sInsertIndex ins i)+ SInsZ -> SIS+ SInsS ins -> \case+ SIZ -> SIZ+ SIS i -> SIS (sInsertIndex ins i) -- | Helper type family for the implementation of 'DeleteIndex', to get -- around the lack of case statements at the type level.-type family SuccDeletedIx (b :: k) (bs :: [k]) (x :: k) (y :: k) (del :: DeletedIx bs x y) :: DeletedIx (b ': bs) x y where- SuccDeletedIx b bs x x 'GotDeleted = 'GotDeleted- SuccDeletedIx b bs x y ('NotDeleted i) = 'NotDeleted ('IS i)+type family+ SuccDeletedIx (b :: k) (bs :: [k]) (x :: k) (y :: k) (del :: DeletedIx bs x y) ::+ DeletedIx (b ': bs) x y+ where+ SuccDeletedIx b bs x x 'GotDeleted = 'GotDeleted+ SuccDeletedIx b bs x y ('NotDeleted i) = 'NotDeleted ('IS i) -- | Type-level version of 'deleteIndex'. Because of how GADTs and type -- families interact, the type-level lists and kinds of the insertion and -- index must be provided.-type family DeleteIndex (as :: [k]) (bs :: [k]) (x :: k) (y :: k) (del :: Delete as bs x) (i :: Index as y) :: DeletedIx bs x y where- DeleteIndex (x ': bs) bs x x 'DelZ 'IZ = 'GotDeleted- DeleteIndex (x ': bs) bs x y 'DelZ ('IS i) = 'NotDeleted i- DeleteIndex (y ': as) (y ': bs) x y ('DelS del) 'IZ = 'NotDeleted 'IZ- DeleteIndex (b ': as) (b ': bs) x y ('DelS del) ('IS i) = SuccDeletedIx b bs x y (DeleteIndex as bs x y del i)+type family+ DeleteIndex (as :: [k]) (bs :: [k]) (x :: k) (y :: k) (del :: Delete as bs x) (i :: Index as y) ::+ DeletedIx bs x y+ where+ DeleteIndex (x ': bs) bs x x 'DelZ 'IZ = 'GotDeleted+ DeleteIndex (x ': bs) bs x y 'DelZ ('IS i) = 'NotDeleted i+ DeleteIndex (y ': as) (y ': bs) x y ('DelS del) 'IZ = 'NotDeleted 'IZ+ DeleteIndex (b ': as) (b ': bs) x y ('DelS del) ('IS i) =+ SuccDeletedIx b bs x y (DeleteIndex as bs x y del i) -- | Defunctionalization symbol for 'DeleteIndex', expecting only the kind -- variables.@@ -650,38 +692,52 @@ -- | Kind-indexed singleton for 'DeletedIx'. data SDeletedIx (bs :: [k]) (x :: k) (y :: k) :: DeletedIx bs x y -> Type where- SGotDeleted :: SDeletedIx bs x x 'GotDeleted- SNotDeleted :: SIndex bs y i -> SDeletedIx bs x y ('NotDeleted i)+ SGotDeleted :: SDeletedIx bs x x 'GotDeleted+ SNotDeleted :: SIndex bs y i -> SDeletedIx bs x y ('NotDeleted i) -- | Singleton witness for 'DeleteIndex'.-sDeleteIndex- :: SDelete as bs x del- -> SIndex as y i- -> SDeletedIx bs x y (DeleteIndex as bs x y del i)+sDeleteIndex ::+ SDelete as bs x del ->+ SIndex as y i ->+ SDeletedIx bs x y (DeleteIndex as bs x y del i) sDeleteIndex = \case- SDelZ -> \case- SIZ -> SGotDeleted- SIS i -> SNotDeleted i- SDelS del -> \case- SIZ -> SNotDeleted SIZ- SIS i -> case sDeleteIndex del i of- SGotDeleted -> SGotDeleted- SNotDeleted j -> SNotDeleted (SIS j)+ SDelZ -> \case+ SIZ -> SGotDeleted+ SIS i -> SNotDeleted i+ SDelS del -> \case+ SIZ -> SNotDeleted SIZ+ SIS i -> case sDeleteIndex del i of+ SGotDeleted -> SGotDeleted+ SNotDeleted j -> SNotDeleted (SIS j) -- | Helper type family for the implementation of 'SubstituteIndex', to get -- around the lack of case statements at the type level.-type family SuccSubstitutedIx (b :: k) (bs :: [k]) (x :: k) (y :: k) (z :: k) (s :: SubstitutedIx bs x y z) :: SubstitutedIx (b ': bs) x y z where- SuccSubstitutedIx b bs x y x ('GotSubbed i) = 'GotSubbed ('IS i)- SuccSubstitutedIx b bs x y z ('NotSubbed i) = 'NotSubbed ('IS i)+type family+ SuccSubstitutedIx (b :: k) (bs :: [k]) (x :: k) (y :: k) (z :: k) (s :: SubstitutedIx bs x y z) ::+ SubstitutedIx (b ': bs) x y z+ where+ SuccSubstitutedIx b bs x y x ('GotSubbed i) = 'GotSubbed ('IS i)+ SuccSubstitutedIx b bs x y z ('NotSubbed i) = 'NotSubbed ('IS i) -- | Type-level version of 'substituteIndex'. Because of how GADTs and -- type families interact, the type-level lists and kinds of the insertion -- and index must be provided.-type family SubstituteIndex (as :: [k]) (bs :: [k]) (x :: k) (y :: k) (z :: k) (s :: Substitute as bs x y) (i :: Index as z) :: SubstitutedIx bs x y z where- SubstituteIndex (z ': as) (y ': as) z y z 'SubZ 'IZ = 'GotSubbed 'IZ- SubstituteIndex (x ': as) (y ': as) x y z 'SubZ ('IS i) = 'NotSubbed ('IS i)- SubstituteIndex (z ': as) (z ': bs) x y z ('SubS s) 'IZ = 'NotSubbed 'IZ- SubstituteIndex (b ': as) (b ': bs) x y z ('SubS s) ('IS i) = SuccSubstitutedIx b bs x y z (SubstituteIndex as bs x y z s i)+type family+ SubstituteIndex+ (as :: [k])+ (bs :: [k])+ (x :: k)+ (y :: k)+ (z :: k)+ (s :: Substitute as bs x y)+ (i :: Index as z) ::+ SubstitutedIx bs x y z+ where+ SubstituteIndex (z ': as) (y ': as) z y z 'SubZ 'IZ = 'GotSubbed 'IZ+ SubstituteIndex (x ': as) (y ': as) x y z 'SubZ ('IS i) = 'NotSubbed ('IS i)+ SubstituteIndex (z ': as) (z ': bs) x y z ('SubS s) 'IZ = 'NotSubbed 'IZ+ SubstituteIndex (b ': as) (b ': bs) x y z ('SubS s) ('IS i) =+ SuccSubstitutedIx b bs x y z (SubstituteIndex as bs x y z s i) -- | Defunctionalization symbol for 'SubstituteIndex', expecting only the kind -- variables.@@ -696,20 +752,20 @@ -- | Kind-indexed singleton for 'SubstitutedIx'. data SSubstitutedIx (bs :: [k]) (x :: k) (y :: k) (z :: k) :: SubstitutedIx bs x y z -> Type where- SGotSubbed :: SIndex bs y i -> SSubstitutedIx bs z y z ('GotSubbed i)- SNotSubbed :: SIndex bs z i -> SSubstitutedIx bs x y z ('NotSubbed i)+ SGotSubbed :: SIndex bs y i -> SSubstitutedIx bs z y z ('GotSubbed i)+ SNotSubbed :: SIndex bs z i -> SSubstitutedIx bs x y z ('NotSubbed i) -- | Singleton witness for 'SubstituteIndex'.-sSubstituteIndex- :: SSubstitute as bs x y s- -> SIndex as z i- -> SSubstitutedIx bs x y z (SubstituteIndex as bs x y z s i)+sSubstituteIndex ::+ SSubstitute as bs x y s ->+ SIndex as z i ->+ SSubstitutedIx bs x y z (SubstituteIndex as bs x y z s i) sSubstituteIndex = \case- SSubZ -> \case- SIZ -> SGotSubbed SIZ- SIS i -> SNotSubbed (SIS i)- SSubS s -> \case- SIZ -> SNotSubbed SIZ- SIS i -> case sSubstituteIndex s i of- SGotSubbed j -> SGotSubbed (SIS j)- SNotSubbed j -> SNotSubbed (SIS j)+ SSubZ -> \case+ SIZ -> SGotSubbed SIZ+ SIS i -> SNotSubbed (SIS i)+ SSubS s -> \case+ SIZ -> SNotSubbed SIZ+ SIS i -> case sSubstituteIndex s i of+ SGotSubbed j -> SGotSubbed (SIS j)+ SNotSubbed j -> SNotSubbed (SIS j)
src/Data/Type/List/Sublist.hs view
@@ -1,19 +1,19 @@-{-# LANGUAGE EmptyCase #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE EmptyCase #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeInType #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE ViewPatterns #-} -- | -- Module : Data.Type.List.Sublist@@ -27,67 +27,112 @@ -- Witnesses regarding sublists of lists. module Data.Type.List.Sublist ( -- * Prefix and Suffix+ -- ** Prefix- Prefix(..), IsPrefix, autoPrefix- , takeRec, prefixLens, takeIndex, weakenIndex- , prefixShape+ Prefix (..),+ IsPrefix,+ autoPrefix,+ takeRec,+ prefixLens,+ takeIndex,+ weakenIndex,+ prefixShape,+ -- ** Suffix- , Suffix(..), IsSuffix, autoSuffix- , dropRec, suffixLens, dropIndex, shiftIndex+ Suffix (..),+ IsSuffix,+ autoSuffix,+ dropRec,+ suffixLens,+ dropIndex,+ shiftIndex,+ -- * Append- , Append(..), IsAppend, autoAppend, withAppend- , prefixToAppend, suffixToAppend- , appendToPrefix, appendToSuffix, splitAppend- , appendShape+ Append (..),+ IsAppend,+ autoAppend,+ withAppend,+ prefixToAppend,+ suffixToAppend,+ appendToPrefix,+ appendToSuffix,+ splitAppend,+ appendShape,+ -- ** Application- , splitRec, appendRec, splitRecIso- , splitIndex+ splitRec,+ appendRec,+ splitRecIso,+ splitIndex,+ -- ** Witnesses+ -- *** Singletons- , pattern AppendWit- , appendWit, implyAppend, unAppendWit+ pattern AppendWit,+ appendWit,+ implyAppend,+ unAppendWit,+ -- *** Vinyl- , pattern AppendWitV- , appendWitV, implyAppendV, unAppendWitV+ pattern AppendWitV,+ appendWitV,+ implyAppendV,+ unAppendWitV,+ -- *** Both- , pattern AppendWit'- , convertAppends- , AppendedTo+ pattern AppendWit',+ convertAppends,+ AppendedTo,+ -- * Interleave- , Interleave(..), IsInterleave, autoInterleave- , interleaveRec, unweaveRec, interleaveRecIso- , injectIndexL, injectIndexR, unweaveIndex- , interleavedIxes, swapInterleave- , interleaveShapes+ Interleave (..),+ IsInterleave,+ autoInterleave,+ interleaveRec,+ unweaveRec,+ interleaveRecIso,+ injectIndexL,+ injectIndexR,+ unweaveIndex,+ interleavedIxes,+ swapInterleave,+ interleaveShapes,+ -- * Subset- , Subset(..), IsSubset, autoSubset- , subsetComplement- , interleaveRToSubset, interleaveLToSubset- , subsetToInterleaveL, subsetToInterleaveR- , subsetRec, getSubset- , subsetShapes- , subsetIxes- , weakenSubsetIndex, strengthenSubsetIndex- ) where+ 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.List.Singletons (SList(..), type (++))-import Data.Profunctor-import Data.Singletons-import Data.Singletons.Decide-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+import Data.Bifunctor+import Data.Functor.Compose+import Data.Kind+import Data.List.Singletons (SList (..), type (++))+import Data.Profunctor+import Data.Singletons+import Data.Singletons.Decide+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 qualified Data.Vinyl.Recursive as VR+import qualified Data.Vinyl.TypeLevel as V+import GHC.Generics ((:+:) (..))+import Lens.Micro hiding ((%~))+import Lens.Micro.Extras -- | A @'Prefix' as bs@ witnesses that @as@ is a prefix of @bs@. --@@ -106,8 +151,8 @@ -- This is essentially the first half of an 'Append', but is conceptually -- easier to work with. data Prefix :: [k] -> [k] -> Type where- PreZ :: Prefix '[] as- PreS :: Prefix as bs -> Prefix (a ': as) (a ': bs)+ PreZ :: Prefix '[] as+ PreS :: Prefix as bs -> Prefix (a ': as) (a ': bs) deriving instance Show (Prefix as bs) @@ -125,23 +170,23 @@ type IsPrefix as = TyPred (Prefix as) instance Auto (IsPrefix '[]) bs where- auto = PreZ+ auto = PreZ instance Auto (IsPrefix as) bs => Auto (IsPrefix (a ': as)) (a ': bs) where- auto = PreS (auto @_ @(IsPrefix as) @bs)+ 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+ 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 _ -> v Refl+ PreS p -> v p+ Disproved v -> Disproved $ \case+ PreS _ -> v Refl -- | Automatically generate a 'Prefix' if @as@ and @bs@ are known -- statically.@@ -153,12 +198,12 @@ -- | Get the 'Shape' associated with a 'Prefix'. -- -- @since 0.1.3.0-prefixShape- :: Prefix as bs- -> Shape [] as+prefixShape ::+ Prefix as bs ->+ Shape [] as prefixShape = \case- PreZ -> RNil- PreS p -> Proxy :& prefixShape p+ PreZ -> RNil+ PreS p -> Proxy :& prefixShape p -- | A @'Suffix' as bs@ witnesses that @as@ is a suffix of @bs@. --@@ -177,8 +222,8 @@ -- This is essentially the second half of an 'Append', but is conceptually -- easier to work with. data Suffix :: [k] -> [k] -> Type where- SufZ :: Suffix as as- SufS :: Suffix as bs -> Suffix as (b ': bs)+ SufZ :: Suffix as as+ SufS :: Suffix as bs -> Suffix as (b ': bs) deriving instance Show (Suffix as bs) @@ -188,24 +233,24 @@ type IsSuffix as = TyPred (Suffix as) instance Auto (IsSuffix '[]) '[] where- auto = SufZ+ auto = SufZ instance {-# OVERLAPPABLE #-} Auto (IsSuffix (a ': as)) (a ': as) where- auto = SufZ+ auto = SufZ instance {-# OVERLAPPABLE #-} Auto (IsSuffix as) bs => Auto (IsSuffix as) (b ': bs) where- auto = SufS (auto @_ @(IsSuffix as) @bs)+ 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+ 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 -- | Automatically generate a 'Suffix' if @as@ and @bs@ are known -- statically.@@ -238,8 +283,8 @@ -- -- This basically combines 'Prefix' and 'Suffix'. data Append :: [k] -> [k] -> [k] -> Type where- AppZ :: Append '[] as as- AppS :: Append as bs cs -> Append (a ': as) bs (a ': cs)+ AppZ :: Append '[] as as+ AppS :: Append as bs cs -> Append (a ': as) bs (a ': cs) deriving instance Show (Append as bs cs) @@ -265,30 +310,30 @@ type AppendedTo as = TyPP (Append as) instance Auto (IsAppend '[] as) as where- auto = AppZ+ auto = AppZ instance Auto (IsAppend as bs) cs => Auto (IsAppend (a ': as) bs) (a ': cs) where- auto = AppS (auto @_ @(IsAppend as bs) @cs)+ 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+ 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 _ -> v Refl+ 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+ prove ys = withAppend (singProd (sing @as)) (singProd ys) $ \s x -> prodSing s :&: x -- | Automatically generate an 'Append' if @as@, @bs@ and @cs@ are known -- statically.@@ -303,23 +348,23 @@ -- @since 0.1.2.0 appendWit :: Append as bs cs -> (as ++ bs) :~: cs appendWit = \case- AppZ -> Refl- AppS a -> case appendWit a of- Refl -> Refl+ AppZ -> Refl+ AppS a -> case appendWit a of+ Refl -> Refl -- | The inverse of 'appendWit': if we know @(as ++ bs) ~ cs@ (using @++@ -- from "Data.Singletons.Prelude.List"), we can create an @'Append' as bs -- cs@ given structure witnesses 'Sing'. -- -- @since 0.1.2.0-unAppendWit- :: (as ++ bs) ~ cs- => Rec f as- -> Rec f bs- -> Append as bs cs+unAppendWit ::+ (as ++ bs) ~ cs =>+ Rec f as ->+ Rec f bs ->+ Append as bs cs unAppendWit = \case- RNil -> \_ -> AppZ- _ :& xs -> AppS . unAppendWit xs+ RNil -> \_ -> AppZ+ _ :& xs -> AppS . unAppendWit xs -- | A useful pattern synonym for using 'Append' with @++@ from -- "Data.Singletons.Prelude.List".@@ -331,10 +376,12 @@ -- you have @(as ++ bs) ~ cs@ in the context. -- -- @since 0.1.2.0-pattern AppendWit :: forall as bs cs. (RecApplicative as, RecApplicative bs) => (as ++ bs) ~ cs => Append as bs cs+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 #-} -- | 'appendWit' stated as a 'Predicate' implication.@@ -349,23 +396,23 @@ -- @since 0.1.2.0 appendWitV :: Append as bs cs -> (as V.++ bs) :~: cs appendWitV = \case- AppZ -> Refl- AppS a -> case appendWitV a of- Refl -> Refl+ AppZ -> Refl+ AppS a -> case appendWitV a of+ Refl -> Refl -- | The inverse of 'appendWitV': if we know @(as ++ bs) ~ cs@ (using @++@ -- from "Data.Vinyl.TypeLevel"), we can create an @'Append' as bs cs@ given -- structure witnesses 'Sing'. -- -- @since 0.1.2.0-unAppendWitV- :: (as V.++ bs) ~ cs- => Rec f as- -> Rec f bs- -> Append as bs cs+unAppendWitV ::+ (as V.++ bs) ~ cs =>+ Rec f as ->+ Rec f bs ->+ Append as bs cs unAppendWitV = \case- RNil -> \_ -> AppZ- _ :& xs -> AppS . unAppendWitV xs+ RNil -> \_ -> AppZ+ _ :& xs -> AppS . unAppendWitV xs -- | A useful pattern synonym for using 'Append' with @++@ from -- "Data.Vinyl.TypeLevel".@@ -377,10 +424,12 @@ -- you have @(as ++ bs) ~ cs@ in the context. -- -- @since 0.1.2.0-pattern AppendWitV :: forall as bs cs. (RecApplicative as, RecApplicative bs) => (as V.++ bs) ~ cs => Append as bs cs+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 #-} -- | Combine the powers of 'AppendWit' and 'AppendWitV' by matching on an@@ -390,10 +439,15 @@ -- by transitive property. -- -- @since 0.1.2.0-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))+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 #-} -- | 'appendWitV' stated as a 'Predicate' implication.@@ -407,26 +461,26 @@ -- "Data.Vinyl.TypeLevel". convertAppends :: Append as bs cs -> (as ++ bs) :~: (as V.++ bs) convertAppends a = case appendWit a of- Refl -> case appendWitV a of- Refl -> Refl+ Refl -> case appendWitV a of+ Refl -> Refl -- | Given @as@ and @bs@, create an @'Append' as bs cs@ with, with @cs@ -- existentially quantified 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)+ RNil -> \ys f -> f ys AppZ+ x :& xs -> \ys f -> withAppend xs ys $ \zs a ->+ f (x :& zs) (AppS a) -- | Get the 'Shape' associated with an 'Append''s prefix. -- -- @since 0.1.3.0-appendShape- :: Append as bs cs- -> Shape [] as+appendShape ::+ Append as bs cs ->+ Shape [] as appendShape = \case- AppZ -> RNil- AppS a -> Proxy :& appendShape a+ AppZ -> RNil+ AppS a -> Proxy :& appendShape a -- | Witness an isomorphism between 'Rec' and two parts that compose it. --@@ -441,137 +495,141 @@ -- This can be used with the combinators from the lens library. -- -- The 'Append' tells the point to split the 'Rec' at.-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 ::+ (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)) -- | Split a 'Rec' into a prefix and suffix. Basically 'takeRec' -- and 'dropRec' combined.-splitRec- :: Append as bs cs- -> Rec f cs- -> (Rec f as, Rec f bs)+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+ AppZ -> (RNil,)+ AppS a -> \case+ x :& xs -> first (x :&) . splitRec a $ xs -- | Append two 'Rec's together according to an 'Append'.-appendRec- :: Append as bs cs- -> Rec f as- -> Rec f bs- -> Rec f cs+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+ AppZ -> \_ -> id+ AppS a -> \case+ x :& xs -> (x :&) . appendRec a xs -- | Convert a 'Prefix' to an 'Append', with an existential @bs@.-prefixToAppend- :: Prefix as cs- -> (forall bs. Append as bs cs -> r)- -> r+prefixToAppend ::+ Prefix as cs ->+ (forall bs. Append as bs cs -> r) ->+ r prefixToAppend = \case- PreZ -> ($ AppZ)- PreS p -> \f -> prefixToAppend p (f . AppS)+ PreZ -> ($ AppZ)+ PreS p -> \f -> prefixToAppend p (f . AppS) -- | Convert a 'Suffix' to an 'Append', with an existential @as@.-suffixToAppend- :: Suffix bs cs- -> (forall as. Append as bs cs -> r)- -> r+suffixToAppend ::+ Suffix bs cs ->+ (forall as. Append as bs cs -> r) ->+ r suffixToAppend = \case- SufZ -> ($ AppZ)- SufS s -> \f -> suffixToAppend s (f . AppS)+ SufZ -> ($ AppZ)+ SufS s -> \f -> suffixToAppend s (f . AppS) -- | Split an 'Append' into a 'Prefix' and 'Suffix'. Basically -- 'appendToPrefix' and 'appendToSuffix' at the same time.-splitAppend- :: Append as bs cs- -> (Prefix as cs, Suffix bs cs)+splitAppend ::+ Append as bs cs ->+ (Prefix as cs, Suffix bs cs) splitAppend = \case- AppZ -> (PreZ, SufZ)- AppS a -> bimap PreS SufS . splitAppend $ a+ AppZ -> (PreZ, SufZ)+ AppS a -> bimap PreS SufS . splitAppend $ a -- | Convert an 'Append' to a 'Prefix', forgetting the suffix. appendToPrefix :: Append as bs cs -> Prefix as cs appendToPrefix = \case- AppZ -> PreZ- AppS a -> PreS . appendToPrefix $ a+ AppZ -> PreZ+ AppS a -> PreS . appendToPrefix $ a -- | Convert an 'Append' to a 'Suffix', forgetting the prefix appendToSuffix :: Append as bs cs -> Suffix bs cs appendToSuffix = \case- AppZ -> SufZ- AppS a -> SufS . appendToSuffix $ a+ AppZ -> SufZ+ AppS a -> SufS . appendToSuffix $ a -- | Split an 'Index' by an 'Append'. If the 'Index' was in the first part -- of the list, it'll return 'Left'. If it was in the second part, it'll -- return 'Right'. -- -- This is essentially 'takeIndex' and 'dropIndex' at the same time.-splitIndex- :: Append as bs cs- -> Index cs x- -> Either (Index as x) (Index bs x)+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+ AppZ -> Right+ AppS a -> \case+ IZ -> Left IZ+ IS i -> first IS . splitIndex a $ i -- | Shave off the final inhabitants of an 'Index', keeping only indices -- a part of a given prefix. If the index is out of range, 'Nothing' will -- be returned. -- -- This is essentially 'splitIndex', but taking only 'Left' results.-takeIndex- :: Prefix as bs- -> Index bs x- -> Maybe (Index as x)-takeIndex p i = prefixToAppend p $ either Just (const Nothing)- . (`splitIndex` i)+takeIndex ::+ Prefix as bs ->+ Index bs x ->+ Maybe (Index as x)+takeIndex p i =+ prefixToAppend p $+ either Just (const Nothing)+ . (`splitIndex` i) -- | Shave off the initial inhabitants of an 'Index', keeping only indices -- a part of a given suffix If the index is out of range, 'Nothing' will -- be returned. -- -- This is essentially 'splitIndex', but taking only 'Right' results.-dropIndex- :: Suffix as bs- -> Index bs x- -> Maybe (Index as x)-dropIndex s i = suffixToAppend s $ either (const Nothing) Just- . (`splitIndex` i)+dropIndex ::+ Suffix as bs ->+ Index bs x ->+ Maybe (Index as x)+dropIndex s i =+ suffixToAppend s $+ either (const Nothing) Just+ . (`splitIndex` i) -- | An index pointing to a given item in a prefix is also an index -- pointing to the same item in the full list. This "weakens" the bounds -- of an index, widening the list at the end but preserving the original -- index. This is the inverse of 'takeIndex'.-weakenIndex- :: Prefix as bs- -> Index as x- -> Index bs x+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)+ PreZ -> \case {}+ PreS p -> \case+ IZ -> IZ+ IS i -> IS (weakenIndex p i) -- | An index pointing to a given item in a suffix can be transformed into -- an index pointing to the same item in the full list. This is the -- inverse of 'dropIndex'.-shiftIndex- :: Suffix as bs- -> Index as x- -> Index bs x+shiftIndex ::+ Suffix as bs ->+ Index as x ->+ Index bs x shiftIndex = \case- SufZ -> id- SufS s -> IS . shiftIndex s+ SufZ -> id+ SufS s -> IS . shiftIndex s -- | A @'Interleave' as bs cs@ witnesses that @cs@ is @as@ interleaved with -- @bs@. It is constructed by selectively zipping items from @as@ and @bs@@@ -591,9 +649,9 @@ -- -- @since 0.1.1.0 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)+ 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) @@ -604,63 +662,63 @@ type IsInterleave as bs = TyPred (Interleave as bs) instance Auto (IsInterleave '[] '[]) '[] where- auto = IntZ+ auto = IntZ -- | Prefers 'IntL' if there is an ambiguity. instance Auto (IsInterleave as bs) cs => Auto (IsInterleave (a ': as) bs) (a ': cs) where- auto = IntL (auto @_ @(IsInterleave as bs) @cs)+ 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)+ 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+ 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 _ -> 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+ 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 _ -> 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+ 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 _ -> v Refl+ IntL i -> v i IntR i -> u i Disproved u -> Disproved $ \case- IntL _ -> v Refl+ 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 -- | Automatically generate an 'Interleave' if @as@, @bs@, and @cs@ are -- known statically.@@ -683,13 +741,13 @@ -- @since 0.1.1.0 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+ 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 -- | Given a 'Rec', disinterleave it into two 'Rec's corresponding to an -- 'Interleave'.@@ -697,12 +755,12 @@ -- @since 0.1.1.0 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+ 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 -- | Turn an 'Interleave' into a 'Rec' of indices from either sublist. --@@ -711,11 +769,17 @@ -- @since 0.1.2.0 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)+ 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) -- | Interleave an 'Index' on @as@ into a full index on @cs@, which is @as@ -- interleaved with @bs@.@@ -723,11 +787,11 @@ -- @since 0.1.1.0 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+ IntZ -> \case {}+ IntL m -> \case+ IZ -> IZ+ IS i -> IS (injectIndexL m i)+ IntR m -> IS . injectIndexL m -- | Interleave an 'Index' on @bs@ into a full index on @cs@, which is @as@ -- interleaved with @bs@.@@ -735,11 +799,11 @@ -- @since 0.1.1.0 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)+ IntZ -> \case {}+ IntL m -> IS . injectIndexR m+ IntR m -> \case+ IZ -> IZ+ IS i -> IS (injectIndexR m i) -- | Given an index on @cs@, disinterleave it into either an index on @as@ -- or on @bs@.@@ -747,13 +811,13 @@ -- @since 0.1.1.0 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+ 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 -- | Witness an isomorphism between 'Rec' and two parts that interleave it. --@@ -770,38 +834,38 @@ -- The 'Interleave' tells how to unweave the 'Rec'. -- -- @since 0.1.1.0-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 ::+ (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)) -- | Swap the two halves of an 'Interleave'. -- -- @since 0.1.3.0-swapInterleave- :: Interleave as bs cs- -> Interleave bs as cs+swapInterleave ::+ Interleave as bs cs ->+ Interleave bs as cs swapInterleave = \case- IntZ -> IntZ- IntL i -> IntR $ swapInterleave i- IntR i -> IntL $ swapInterleave i+ IntZ -> IntZ+ IntL i -> IntR $ swapInterleave i+ IntR i -> IntL $ swapInterleave i -- | Get the 'Shape's associated with an 'Interleave'. -- -- @since 0.1.3.0-interleaveShapes- :: Interleave as bs cs- -> (Shape [] as, Shape [] bs, Shape [] cs)+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)+ 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) -- | A @'Subset' as bs@ witnesses that @as@ is some subset of @bs@, with -- items in the same order. It is constructed by specifying@@ -823,60 +887,59 @@ -- -- @since 0.1.3.0 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)+ SubsetNil :: Subset '[] '[]+ SubsetNo :: Subset as bs -> Subset as (b ': bs)+ SubsetYes :: Subset as bs -> Subset (a ': as) (a ': bs) -- | Drop the right side of an 'Interleave', leaving only the left side. interleaveLToSubset :: Interleave as bs cs -> Subset as cs interleaveLToSubset = \case- IntZ -> SubsetNil- IntL i -> SubsetYes . interleaveLToSubset $ i- IntR i -> SubsetNo . interleaveLToSubset $ i+ IntZ -> SubsetNil+ IntL i -> SubsetYes . interleaveLToSubset $ i+ IntR i -> SubsetNo . interleaveLToSubset $ i -- | Drop the left side of an 'Interleave', leaving only the right side. interleaveRToSubset :: Interleave as bs cs -> Subset bs cs interleaveRToSubset = \case- IntZ -> SubsetNil- IntL i -> SubsetNo . interleaveRToSubset $ i- IntR i -> SubsetYes . interleaveRToSubset $ i+ IntZ -> SubsetNil+ IntL i -> SubsetNo . interleaveRToSubset $ i+ IntR i -> SubsetYes . interleaveRToSubset $ i -- | Convert a 'Subset' into an left 'Interleave', recovering the dropped -- items.-subsetToInterleaveL- :: Subset as cs- -> (forall bs. Interleave as bs cs -> r)- -> r+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)+ SubsetNil -> \f -> f IntZ+ SubsetNo s -> \f -> subsetToInterleaveL s (f . IntR)+ SubsetYes s -> \f -> subsetToInterleaveL s (f . IntL) -- | Convert a 'Subset' into an right 'Interleave', recovering the dropped -- items.-subsetToInterleaveR- :: Subset bs cs- -> (forall as. Interleave as bs cs -> r)- -> r+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)+ SubsetNil -> \f -> f IntZ+ SubsetNo s -> \f -> subsetToInterleaveR s (f . IntL)+ SubsetYes s -> \f -> subsetToInterleaveR s (f . IntR) -- | @as@ is a subset of @cs@; this function recovers @bs@, the subset of -- @cs@ that is not @as@.-subsetComplement- :: Subset as cs- -> (forall bs. Subset bs cs -> r)- -> r+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)+ SubsetNil -> \f -> f SubsetNil+ SubsetNo s -> \f -> subsetComplement s (f . SubsetYes)+ SubsetYes s -> \f -> subsetComplement s (f . SubsetNo) deriving instance Show (Subset as bs) - -- | A type-level predicate that a given list is a "superset" of @as@, in -- correct order --@@ -884,37 +947,37 @@ type IsSubset as = TyPred (Subset as) instance Auto (IsSubset '[]) '[] where- auto = SubsetNil+ auto = SubsetNil instance {-# OVERLAPPING #-} Auto (IsSubset as) bs => Auto (IsSubset as) (b ': bs) where- auto = SubsetNo (auto @_ @(IsSubset as) @bs)+ 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)+ 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+ 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+ Proved s -> Proved $ SubsetNo s Disproved u -> Disproved $ \case- SubsetNo s -> u s- SubsetYes _ -> v Refl+ 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 -- | Automatically generate an 'Subset' if @as@ and @bs@ are known -- statically.@@ -924,54 +987,55 @@ -- | A lens into a subset of a record, indicated by a 'Subset'. 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+ 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 -- | Take a subset out of a 'Rec'. An alias for @'view' ('subsetRec' s)@.-getSubset- :: Subset as bs- -> Rec f bs- -> Rec f as+getSubset ::+ Subset as bs ->+ Rec f bs ->+ Rec f as getSubset = view . subsetRec -- | Get all of the indices of all the items in a 'Subset'.-subsetIxes- :: Subset as bs- -> Rec (Index bs) as+subsetIxes ::+ Subset as bs ->+ Rec (Index bs) as subsetIxes s = getSubset s . imapProd const $ sp where (_, sp) = subsetShapes s -- | Get the 'Shape's associated with a 'Subset'.-subsetShapes- :: Subset as bs- -> (Shape [] as, Shape [] bs)+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+ SubsetNil -> (RNil, RNil)+ SubsetNo s -> second (Proxy :&) $ subsetShapes s+ SubsetYes s -> bimap (Proxy :&) (Proxy :&) $ subsetShapes s -- | Because @as@ is a subset of @bs@, an index into @as@ should also be an -- index into @bs@. This performs that transformation. -- -- This is like a version of 'injectIndexL' or 'injectIndexR', for -- 'Subset'.-weakenSubsetIndex- :: Subset as bs- -> Index as a- -> Index bs a+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+ SubsetNil -> \case {}+ SubsetNo s -> IS . weakenSubsetIndex s+ SubsetYes s -> \case+ IZ -> IZ+ IS i -> IS $ weakenSubsetIndex s i -- | Because @as@ is a subset of @bs@, we can /sometimes/ transform an -- index into @bs@ into an index into @as@. This performs that@@ -985,15 +1049,15 @@ -- the exact same item (positionlly) in the list, if it is possible. -- -- This is like a version of 'unweaveIndex', but for 'Subset'.-strengthenSubsetIndex- :: Subset as bs- -> Index bs a- -> Maybe (Index as a)+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+ SubsetNil -> \case {}+ SubsetNo s -> \case+ IZ -> Nothing+ IS i -> strengthenSubsetIndex s i+ SubsetYes s -> \case+ IZ -> Just IZ+ IS i -> IS <$> strengthenSubsetIndex s i