packages feed

list-witnesses 0.1.1.1 → 0.1.2.0

raw patch · 4 files changed

+578/−46 lines, 4 filesdep +functor-productsdep ~decidablePVP ok

version bump matches the API change (PVP)

Dependencies added: functor-products

Dependency ranges changed: decidable

API changes (from Hackage documentation)

+ Data.Type.List.Edit: autoDelete :: forall as bs x. Auto (IsDelete as bs) x => Delete as bs x
+ Data.Type.List.Edit: autoInsert :: forall as bs x. Auto (IsInsert as bs) x => Insert as bs x
+ Data.Type.List.Edit: autoSubstitute :: forall as bs x y. Auto (IsSubstitute as bs x) y => Substitute as bs x y
+ Data.Type.List.Edit: instance forall k (as :: [k]) (bs :: [k]) (x :: k) (a :: k). Data.Type.Predicate.Auto.Auto (Data.Type.List.Edit.IsDelete as bs) x => Data.Type.Predicate.Auto.Auto (Data.Type.List.Edit.IsDelete (a : as) (a : bs)) x
+ Data.Type.List.Edit: instance forall k (as :: [k]) (bs :: [k]) (x :: k) (a :: k). Data.Type.Predicate.Auto.Auto (Data.Type.List.Edit.IsInsert as bs) x => Data.Type.Predicate.Auto.Auto (Data.Type.List.Edit.IsInsert (a : as) (a : bs)) x
+ Data.Type.List.Edit: instance forall k (as :: [k]) (bs :: [k]) (x :: k) (y :: k) (c :: k). Data.Type.Predicate.Auto.Auto (Data.Type.List.Edit.IsSubstitute as bs x) y => Data.Type.Predicate.Auto.Auto (Data.Type.List.Edit.IsSubstitute (c : as) (c : bs) x) y
+ Data.Type.List.Edit: instance forall k (as :: [k]) (bs :: [k]). (Data.Singletons.Decide.SDecide k, Data.Singletons.Internal.SingI as, Data.Singletons.Internal.SingI bs) => Data.Type.Predicate.Decidable (Data.Type.List.Edit.IsDelete as bs)
+ Data.Type.List.Edit: instance forall k (as :: [k]) (bs :: [k]). (Data.Singletons.Decide.SDecide k, Data.Singletons.Internal.SingI as, Data.Singletons.Internal.SingI bs) => Data.Type.Predicate.Decidable (Data.Type.List.Edit.IsInsert as bs)
+ Data.Type.List.Edit: instance forall k (as :: [k]) (x :: k). Data.Type.Predicate.Auto.Auto (Data.Type.List.Edit.IsInsert as (x : as)) x
+ Data.Type.List.Edit: instance forall k (as :: [k]). (Data.Singletons.Decide.SDecide k, Data.Singletons.Internal.SingI as) => Data.Type.Predicate.Decidable (Data.Type.Predicate.Param.Found (Data.Type.List.Edit.DeletedFrom as))
+ Data.Type.List.Edit: instance forall k (as :: [k]). (Data.Singletons.Decide.SDecide k, Data.Singletons.Internal.SingI as) => Data.Type.Predicate.Decidable (Data.Type.Predicate.Param.Found (Data.Type.List.Edit.InsertedInto as))
+ Data.Type.List.Edit: instance forall k (x :: k) (as :: [k]) (y :: k). Data.Type.Predicate.Auto.Auto (Data.Type.List.Edit.IsSubstitute (x : as) (y : as) x) y
+ Data.Type.List.Edit: instance forall k (x :: k) (as :: [k]). Data.Type.Predicate.Auto.Auto (Data.Type.List.Edit.IsDelete (x : as) as) x
+ Data.Type.List.Edit: type DeletedFrom (as :: [k]) = (TyPP (Delete as) :: ParamPred [k] k)
+ Data.Type.List.Edit: type InsertedInto (as :: [k]) = (TyPP (Insert as) :: ParamPred [k] k)
+ Data.Type.List.Edit: type IsDelete as bs = TyPred (Delete as bs)
+ Data.Type.List.Edit: type IsInsert as bs = TyPred (Insert as bs)
+ Data.Type.List.Edit: type IsSubstitute as bs x = TyPred (Substitute as bs x)
+ Data.Type.List.Sublist: appendWit :: Append as bs cs -> (as ++ bs) :~: cs
+ Data.Type.List.Sublist: appendWitV :: Append as bs cs -> (as ++ bs) :~: cs
+ Data.Type.List.Sublist: autoAppend :: forall as bs cs. Auto (IsAppend as bs) cs => Append as bs cs
+ Data.Type.List.Sublist: autoInterleave :: forall as bs cs. Auto (IsInterleave as bs) cs => Interleave as bs cs
+ Data.Type.List.Sublist: autoPrefix :: forall as bs. Auto (IsPrefix as) bs => Prefix as bs
+ Data.Type.List.Sublist: autoSuffix :: forall as bs. Auto (IsSuffix as) bs => Suffix as bs
+ Data.Type.List.Sublist: convertAppends :: Append as bs cs -> (as ++ bs) :~: (as ++ bs)
+ Data.Type.List.Sublist: implyAppend :: IsAppend as bs --> EqualTo (as ++ bs)
+ Data.Type.List.Sublist: implyAppendV :: IsAppend as bs --> EqualTo (as ++ bs)
+ Data.Type.List.Sublist: instance Data.Type.Predicate.Auto.Auto (Data.Type.List.Sublist.IsInterleave '[] '[]) '[]
+ Data.Type.List.Sublist: instance forall a (as :: [a]) (bs :: [a]) (b :: a). Data.Type.Predicate.Auto.Auto (Data.Type.List.Sublist.IsSuffix as) bs => Data.Type.Predicate.Auto.Auto (Data.Type.List.Sublist.IsSuffix as) (b : bs)
+ Data.Type.List.Sublist: instance forall a (as :: [a]) (bs :: [a]) (cs :: [a]) (b :: a). Data.Type.Predicate.Auto.Auto (Data.Type.List.Sublist.IsInterleave as bs) cs => Data.Type.Predicate.Auto.Auto (Data.Type.List.Sublist.IsInterleave as (b : bs)) (b : cs)
+ Data.Type.List.Sublist: instance forall a1 (as :: [a1]) (bs :: [a1]) (a2 :: a1). Data.Type.Predicate.Auto.Auto (Data.Type.List.Sublist.IsPrefix as) bs => Data.Type.Predicate.Auto.Auto (Data.Type.List.Sublist.IsPrefix (a2 : as)) (a2 : bs)
+ Data.Type.List.Sublist: instance forall a1 (as :: [a1]) (bs :: [a1]) (cs :: [a1]) (a2 :: a1). Data.Type.Predicate.Auto.Auto (Data.Type.List.Sublist.IsAppend as bs) cs => Data.Type.Predicate.Auto.Auto (Data.Type.List.Sublist.IsAppend (a2 : as) bs) (a2 : cs)
+ Data.Type.List.Sublist: instance forall a1 (as :: [a1]) (bs :: [a1]) (cs :: [a1]) (a2 :: a1). Data.Type.Predicate.Auto.Auto (Data.Type.List.Sublist.IsInterleave as bs) cs => Data.Type.Predicate.Auto.Auto (Data.Type.List.Sublist.IsInterleave (a2 : as) bs) (a2 : cs)
+ Data.Type.List.Sublist: instance forall k (as :: [k]) (bs :: [k]). (Data.Singletons.Decide.SDecide k, Data.Singletons.Internal.SingI as, Data.Singletons.Internal.SingI bs) => Data.Type.Predicate.Decidable (Data.Type.List.Sublist.IsAppend as bs)
+ Data.Type.List.Sublist: instance forall k (as :: [k]) (bs :: [k]). (Data.Singletons.Decide.SDecide k, Data.Singletons.Internal.SingI as, Data.Singletons.Internal.SingI bs) => Data.Type.Predicate.Decidable (Data.Type.List.Sublist.IsInterleave as bs)
+ Data.Type.List.Sublist: instance forall k (as :: [k]). (Data.Singletons.Decide.SDecide k, Data.Singletons.Internal.SingI as) => Data.Type.Predicate.Decidable (Data.Type.List.Sublist.IsPrefix as)
+ Data.Type.List.Sublist: instance forall k (as :: [k]). (Data.Singletons.Decide.SDecide k, Data.Singletons.Internal.SingI as) => Data.Type.Predicate.Decidable (Data.Type.List.Sublist.IsSuffix as)
+ Data.Type.List.Sublist: instance forall k (as :: [k]). Data.Singletons.Internal.SingI as => Data.Type.Predicate.Decidable (Data.Type.Predicate.Param.Found (Data.Type.List.Sublist.AppendedTo as))
+ Data.Type.List.Sublist: instance forall k (as :: [k]). Data.Singletons.Internal.SingI as => Data.Type.Predicate.Provable (Data.Type.Predicate.Param.Found (Data.Type.List.Sublist.AppendedTo as))
+ Data.Type.List.Sublist: instance forall k (as :: [k]). Data.Type.Predicate.Auto.Auto (Data.Type.List.Sublist.IsAppend '[] as) as
+ Data.Type.List.Sublist: instance forall k (as :: [k]). Data.Type.Predicate.Auto.Auto (Data.Type.List.Sublist.IsSuffix as) as
+ Data.Type.List.Sublist: instance forall k (bs :: [k]). Data.Type.Predicate.Auto.Auto (Data.Type.List.Sublist.IsPrefix '[]) bs
+ Data.Type.List.Sublist: interleavedIxes :: Interleave as bs cs -> Rec (Index as :+: Index bs) cs
+ Data.Type.List.Sublist: pattern AppendWit' :: forall as bs cs. (RecApplicative as, RecApplicative bs) => ((as ++ bs) ~ cs, (as ++ bs) ~ cs) => Append as bs cs
+ Data.Type.List.Sublist: type AppendedTo as = TyPP (Append as)
+ Data.Type.List.Sublist: type IsAppend as bs = TyPred (Append as bs)
+ Data.Type.List.Sublist: type IsInterleave as bs = TyPred (Interleave as bs)
+ Data.Type.List.Sublist: type IsPrefix as = TyPred (Prefix as)
+ Data.Type.List.Sublist: type IsSuffix as = TyPred (Suffix as)
+ Data.Type.List.Sublist: unAppendWit :: (as ++ bs) ~ cs => Rec f as -> Rec f bs -> Append as bs cs
+ Data.Type.List.Sublist: unAppendWitV :: (as ++ bs) ~ cs => Rec f as -> Rec f bs -> Append as bs cs
+ Data.Type.List.Sublist: withAppend :: Rec f as -> Rec f bs -> (forall cs. Rec f cs -> Append as bs cs -> r) -> r

Files

CHANGELOG.md view
@@ -1,6 +1,19 @@ Changelog ========= +Version 0.1.2.0+---------------++*August 12, 2019*++<https://github.com/mstksg/list-witnesses/releases/tag/v0.1.2.0>++*   Add predicates (`IsInsert`, `IsPrefix`, etc.) and `Auto` and `Decidable`+    instances for most of the data types, for auto-generation and searches.+*   Add some functions for creating `Append`s and witnesses of concatenation+    type families from `Append`s.+*   `interleavedIxes`, for more manipulation of `Interleave`+ Version 0.1.1.1 --------------- 
list-witnesses.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: a6892eb45e6aae7a7e7c3f4b23c95bdd2299a3a95a190137567cd326e5045529+-- hash: 7abc29a51e67cb59dca3b968d5864b7bcfd1126df6a3bb4166c3eddd2999129f  name:           list-witnesses-version:        0.1.1.1+version:        0.1.2.0 synopsis:       Witnesses for working with type-level lists description:    Collection of assorted inductive witnesses and functions for working with                 type-level lists.@@ -24,7 +24,7 @@ copyright:      (c) Justin Le 2018 license:        BSD3 license-file:   LICENSE-tested-with:    GHC >= 8.4+tested-with:    GHC >= 8.6 build-type:     Simple extra-source-files:     README.md@@ -45,7 +45,8 @@   ghc-options: -Wall -Wcompat -Wredundant-constraints -Werror=incomplete-patterns   build-depends:       base >=4.7 && <5-    , decidable >=0.1.5+    , decidable >=0.2+    , functor-products     , microlens     , profunctors     , singletons
src/Data/Type/List/Edit.hs view
@@ -1,14 +1,19 @@-{-# LANGUAGE EmptyCase            #-}-{-# LANGUAGE GADTs                #-}-{-# LANGUAGE KindSignatures       #-}-{-# LANGUAGE LambdaCase           #-}-{-# LANGUAGE RankNTypes           #-}-{-# LANGUAGE ScopedTypeVariables  #-}-{-# LANGUAGE StandaloneDeriving   #-}-{-# LANGUAGE TypeFamilies         #-}-{-# LANGUAGE TypeInType           #-}-{-# LANGUAGE TypeOperators        #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE EmptyCase             #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE GADTs                 #-}+{-# LANGUAGE KindSignatures        #-}+{-# LANGUAGE LambdaCase            #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes            #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE StandaloneDeriving    #-}+{-# LANGUAGE TypeApplications      #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeInType            #-}+{-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE TypeSynonymInstances  #-}+{-# LANGUAGE UndecidableInstances  #-}  -- | -- Module      : Data.Type.List.Edit@@ -22,13 +27,17 @@ -- Witnesses regarding single-item edits of lists. module Data.Type.List.Edit (   -- * Simple edits-    Insert(..)-  , Delete(..)+    Insert(..), autoInsert+  , Delete(..), autoDelete   , insToDel   , delToIns-  , Substitute(..)+  , Substitute(..), autoSubstitute   , flipSub   , subToDelIns+  -- ** Predicates+  , IsInsert, InsertedInto+  , IsDelete, DeletedFrom+  , IsSubstitute   -- ** Singletons   , SInsert(..)   , SDelete(..)@@ -61,10 +70,15 @@  import           Data.Kind import           Data.Singletons-import           Data.Type.Universe-import           Data.Vinyl.Core-import           Lens.Micro-import qualified Control.Category      as C+import           Data.Singletons.Decide+import           Data.Singletons.Prelude+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  -- | 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'@@ -86,6 +100,94 @@  deriving instance Show (Insert as bs x) +-- | A type-level predicate that a given value can be used as an insertion+-- to change @as@ to @bs@.+--+-- @since 0.1.2.0+type IsInsert as bs = TyPred (Insert as bs)++instance Auto (IsInsert as (x ': as)) x where+    auto = InsZ++instance Auto (IsInsert as bs) x => Auto (IsInsert (a ': as) (a ': bs)) x where+    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+        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+-- inserting @x@ into @as@ somewhere.+--+-- In other words, @'InsertedInto' as@ is satisfied by @bs@ if you can turn+-- @as@ into @bs@ by inserting one individual item.+--+-- You can find this element (if it exists) using 'search', or the+-- 'Decidable' instance of @'Found' ('InsertedInto' as)@:+--+-- @+-- 'searchTC' :: SingI as => Sing bs -> 'Decision' ('Σ' k ('IsInsert' as bs))+-- @+--+-- This will find you the single element you need to insert into @as@ to+-- get @bs@, if it exists.+--+-- @since 0.1.2.0+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+            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++-- | Automatically generate an 'Insert' if @as@, @bs@ and @x@ are known+-- statically.+--+-- @since 0.1.2.0+autoInsert :: forall as bs x. Auto (IsInsert as bs) x => Insert as bs x+autoInsert = auto @_ @(IsInsert as bs) @x+ -- | Kind-indexed singleton for 'Insert'. data SInsert as bs x :: Insert as bs x -> Type where     SInsZ :: SInsert as (x ': as) x 'InsZ@@ -117,6 +219,54 @@  deriving instance Show (Delete as bs x) +-- | A type-level predicate that a given value can be used as a deletion+-- to change @as@ to @bs@.+--+-- @since 0.1.2.0+type IsDelete as bs = TyPred (Delete as bs)++instance Auto (IsDelete (x ': as) as) x where+    auto = DelZ++instance Auto (IsDelete as bs) x => Auto (IsDelete (a ': as) (a ': bs)) x where+    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)++-- | If @bs@ satisfies @'DeletedFrom' as@, it means that there exists some+-- element @x@ such that @'IsDelete' as bs \@\@ x@: you can get @bs@ by+-- deleting @x@ from @as@ somewhere.+--+-- In other words, @'DeletedFrom' as@ is satisfied by @bs@ if you can turn+-- @as@ into @bs@ by deleting one individual item.+--+-- You can find this element (if it exists) using 'search', or the+-- 'Decidable' instance of @'Found' ('DeletedFrom' as)@.+--+-- @+-- 'searchTC' :: SingI as => Sing bs -> 'Decision' ('Σ' k ('IsDelete' as bs))+-- @+--+-- This will find you the single element you need to delete from @as@ to+-- get @bs@, if it exists.+--+-- @since 0.1.2.0+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 @(Found (InsertedInto bs)) (sing @as)++-- | Automatically generate an 'Delete' if @as@, @bs@ and @x@ are known+-- statically.+--+-- @since 0.1.2.0+autoDelete :: forall as bs x. Auto (IsDelete as bs) x => Delete as bs x+autoDelete = auto @_ @(IsDelete as bs) @x+ -- | Kind-indexed singleton for 'Delete'. data SDelete as bs x :: Delete as bs x -> Type where     SDelZ :: SDelete (x ': as) as x 'DelZ@@ -147,6 +297,26 @@  deriving instance Show (Substitute as bs x y) +-- | A type-level predicate that a given value can be used as+-- a substitution of @x@ to change @as@ to @bs@.+--+-- @since 0.1.2.0+type IsSubstitute as bs x = TyPred (Substitute as bs x)++instance Auto (IsSubstitute (x ': as) (y ': as) x) y where+    auto = SubZ++instance Auto (IsSubstitute as bs x) y => Auto (IsSubstitute (c ': as) (c ': bs) x) y where+    auto = SubS (auto @_ @(IsSubstitute as bs x) @y)++-- | Automatically generate an 'Substitute' if @as@, @bs@, @x@, and @y@ are+-- known statically.+--+-- @since 0.1.2.0+autoSubstitute :: forall as bs x y. Auto (IsSubstitute as bs x) y => Substitute as bs x y+autoSubstitute = auto @_ @(IsSubstitute as bs x) @y++ -- | Kind-indexed singleton for 'Substitute'. data SSubstitute as bs x y :: Substitute as bs x y -> Type where     SSubZ :: SSubstitute (x ': as) (y ': as) x y 'SubZ@@ -193,7 +363,8 @@     id = ENil     xs . ys = compEdit ys xs --- | Reverse an 'Edit' script.  O(n^2).  Please do not use.+-- | Reverse an 'Edit' script.  O(n^2).  Please do not use ever in any+-- circumstance. -- -- TODO: Make O(n) using diff lists. flipEdit :: Edit as bs -> Edit bs as@@ -241,8 +412,8 @@ -- The number of 'SubS' in the index essentially indicates the index to -- edit at. ----- This is similar to 'rlensC' from /vinyl/, but is built explicitly and--- inductively, instead of using typeclass magic.+-- 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@@ -472,9 +643,9 @@     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 'subsituteIndex'.  Because of how GADTs and type--- families interact, the type-level lists and kinds of the insertion and--- index must be provided.+-- | 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 bs x y z (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)
src/Data/Type/List/Sublist.hs view
@@ -1,13 +1,19 @@-{-# LANGUAGE EmptyCase           #-}-{-# LANGUAGE GADTs               #-}-{-# LANGUAGE KindSignatures      #-}-{-# LANGUAGE LambdaCase          #-}-{-# LANGUAGE RankNTypes          #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving  #-}-{-# LANGUAGE TupleSections       #-}-{-# LANGUAGE TypeInType          #-}-{-# LANGUAGE TypeOperators       #-}+{-# 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@@ -22,31 +28,53 @@ module Data.Type.List.Sublist (   -- * Prefix and Suffix   -- ** Prefix-    Prefix(..)+    Prefix(..), IsPrefix, autoPrefix   , takeRec, prefixLens, takeIndex, weakenIndex   -- ** Suffix-  , Suffix(..)+  , Suffix(..), IsSuffix, autoSuffix   , dropRec, suffixLens, dropIndex, shiftIndex   -- * Append-  , Append(..)+  , Append(..), IsAppend, autoAppend, withAppend   , prefixToAppend, suffixToAppend   , appendToPrefix, appendToSuffix, splitAppend   -- ** Application   , splitRec, appendRec, splitRecIso   , splitIndex+  -- ** Witnesses+  -- *** Singletons+  , pattern AppendWit+  , appendWit, implyAppend, unAppendWit+  -- *** Vinyl+  , pattern AppendWitV+  , appendWitV, implyAppendV, unAppendWitV+  -- *** Both+  , pattern AppendWit'+  , convertAppends+  , AppendedTo   -- * Interleave-  , Interleave(..)+  , Interleave(..), IsInterleave, autoInterleave   , interleaveRec, unweaveRec, interleaveRecIso   , injectIndexL, injectIndexR, unweaveIndex+  , interleavedIxes   ) where  import           Data.Bifunctor import           Data.Kind import           Data.Profunctor-import           Data.Type.Universe-import           Data.Vinyl.Core-import           Lens.Micro+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  -- | A @'Prefix' as bs@ witnesses that @as@ is a prefix of @bs@. --@@ -78,6 +106,37 @@ takeRec :: Prefix as bs -> Rec f bs -> Rec f as takeRec p = view (prefixLens p) +-- | A type-level predicate that a given list has @as@ as a prefix.+--+-- @since 0.1.2.0+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++-- | Automatically generate a 'Prefix' if @as@ and @bs@ are known+-- statically.+--+-- @since 0.1.2.0+autoPrefix :: forall as bs. Auto (IsPrefix as) bs => Prefix as bs+autoPrefix = auto @_ @(IsPrefix as) @bs+ -- | A @'Suffix' as bs@ witnesses that @as@ is a suffix of @bs@. -- -- Some examples:@@ -100,6 +159,35 @@  deriving instance Show (Suffix as bs) +-- | A type-level predicate that a given list has @as@ as a suffix.+--+-- @since 0.1.2.0+type IsSuffix as = TyPred (Suffix as)++instance Auto (IsSuffix as) as where+    auto = SufZ++instance 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++-- | Automatically generate a 'Suffix' if @as@ and @bs@ are known+-- statically.+--+-- @since 0.1.2.0+autoSuffix :: forall as bs. Auto (IsSuffix as) bs => Suffix as bs+autoSuffix = auto @_ @(IsSuffix as) @bs+ -- | A lens into the suffix of a 'Rec'. suffixLens :: Suffix as bs -> Lens' (Rec f bs) (Rec f as) suffixLens p = suffixToAppend p $ \a -> splitRecIso a . _2@@ -129,6 +217,181 @@  deriving instance Show (Append as bs cs) +-- | A type-level predicate that a given list is the result of appending of+-- @as@ and @bs@.+--+-- @since 0.1.2.0+type IsAppend as bs = TyPred (Append as bs)++-- | A parameterized predicate that you can use with 'select': With an+-- @'AppendedTo' as@, you can give @bs@ and get @cs@ in return, where @cs@+-- is the appending of @as@ and @bs@.+--+-- Run it with:+--+-- @+-- 'selectTC' :: SingI as => Sing bs -> 'Σ' [k] ('IsAppend' as bs)+-- @+--+-- 'select' for 'AppendedTo' is pretty much just 'withAppend'.+--+-- @since 0.1.2.0+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++-- | Automatically generate an 'Append' if @as@, @bs@ and @cs@ are known+-- statically.+--+-- @since 0.1.2.0+autoAppend :: forall as bs cs. Auto (IsAppend as bs) cs => Append as bs cs+autoAppend = auto @_ @(IsAppend as bs) @cs++-- | Witness that @'Append' as bs cs@ implies @(as ++ bs) ~ cs@, using+-- @++@ from "Data.Singletons.Prelude.List".+--+-- @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++-- | 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 = \case+    RNil    -> \_   -> AppZ+    _ :& xs -> AppS . unAppendWit xs++-- | A useful pattern synonym for using 'Append' with @++@ from+-- "Data.Singletons.Prelude.List".+--+-- As a /pattern/, this brings @(as ++ bs) ~ cs@ into the context whenever+-- you use it to match on an @'Append' as bs cs@.+--+-- As an /expression/, this constructs an @'Append' as bs cs@ as long as+-- 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 <- (appendWit @as @bs @cs -> Refl)+  where+    AppendWit = unAppendWit @as @bs @cs pureShape pureShape+{-# COMPLETE AppendWit #-}++-- | 'appendWit' stated as a 'Predicate' implication.+--+-- @since 0.1.2.0+implyAppend :: IsAppend as bs --> EqualTo (as ++ bs)+implyAppend _ = appendWit++-- | Witness that @'Append' as bs cs@ implies @(as ++ bs) ~ cs@, using+-- @++@ from "Data.Vinyl.TypeLevel".+--+-- @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++-- | 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 = \case+    RNil     -> \_   -> AppZ+    _ :& xs -> AppS . unAppendWitV xs++-- | A useful pattern synonym for using 'Append' with @++@ from+-- "Data.Vinyl.TypeLevel".+--+-- As a /pattern/, this brings @(as ++ bs) ~ cs@ into the context whenever+-- you use it to match on an @'Append' as bs cs@.+--+-- As an /expression/, this constructs an @'Append' as bs cs@ as long as+-- 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 <- (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+-- 'Append' to witness @(as ++ bs) ~ cs@ for /both/ @++@ from+-- "Data.Singletons.Prelude.List" and "Data.Vinyl.TypeLevel".  This also+-- witnesses that @(as ++ bs) ~ (as ++ bs)@ (for the two different @++@s)+-- 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))+  where+    AppendWit' = AppendWit+{-# COMPLETE AppendWitV #-}++-- | 'appendWitV' stated as a 'Predicate' implication.+--+-- @since 0.1.2.0+implyAppendV :: IsAppend as bs --> EqualTo (as V.++ bs)+implyAppendV _ = appendWitV++-- | Given a witness @'Append' as bs cs@, prove that singleton's @++@ from+-- "Data.Singletons.Prelude.List" is the same as vinyl's @++@+-- "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++-- | 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)+ -- | Witness an isomorphism between 'Rec' and two parts that compose it. -- -- Read this type signature as:@@ -278,7 +541,7 @@ -- @bs. It is constructed by selectively zipping items from @as@ and @bs@ -- together, like mergesort or riffle shuffle. ----- You construct a 'Interleave' from @as@ and @bs@ by picking "which item" from+-- You construct an 'Interleave' from @as@ and @bs@ by picking "which item" from -- @as@ and @bs@ to add to @cs@. -- -- Some examples:@@ -298,6 +561,77 @@  deriving instance Show (Interleave as bs cs) +-- | A type-level predicate that a given list is the "interleave" of @as@+-- and @bs@.+--+-- @since 0.1.2.0+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 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++-- | Automatically generate an 'Interleave' if @as@ and @bs@ are known+-- statically.+--+-- @since 0.1.2.0+autoInterleave :: forall as bs cs. Auto (IsInterleave as bs) cs => Interleave as bs cs+autoInterleave = auto @_ @(IsInterleave as bs) @cs+ -- | Given two 'Rec's, interleave the two to create a combined 'Rec'. -- -- @since 0.1.1.0@@ -323,6 +657,19 @@       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.+--+-- Warning: O(n^2)+--+-- @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)  -- | Interleave an 'Index' on @as@ into a full index on @cs@, which is @as@ -- interleaved with @bs@.