parameterized-utils 1.0.0 → 1.0.1
raw patch · 12 files changed
+572/−275 lines, 12 filesdep ~base
Dependency ranges changed: base
Files
- parameterized-utils.cabal +2/−2
- src/Data/Parameterized/Classes.hs +8/−2
- src/Data/Parameterized/Context.hs +221/−66
- src/Data/Parameterized/Context/Safe.hs +73/−45
- src/Data/Parameterized/Context/Unsafe.hs +51/−112
- src/Data/Parameterized/List.hs +26/−2
- src/Data/Parameterized/Map.hs +7/−5
- src/Data/Parameterized/NatRepr.hs +58/−10
- src/Data/Parameterized/TH/GADT.hs +48/−3
- src/Data/Parameterized/TraversableF.hs +2/−3
- src/Data/Parameterized/TraversableFC.hs +20/−21
- test/Test/Context.hs +56/−4
parameterized-utils.cabal view
@@ -1,5 +1,5 @@ Name: parameterized-utils-Version: 1.0.0+Version: 1.0.1 Author: Galois Inc. Maintainer: jhendrix@galois.com Build-type: Simple@@ -30,7 +30,7 @@ library build-depends:- base >= 4.7 && < 4.11,+ base >= 4.7 && < 4.12, th-abstraction >=0.1 && <0.3, containers, deepseq,
src/Data/Parameterized/Classes.hs view
@@ -39,6 +39,7 @@ , fromOrdering -- * Typeclass generalizations , ShowF(..)+ , showsF , HashableF(..) , CoercibleF(..) -- * Optics generalizations@@ -211,8 +212,13 @@ showF :: forall tp . f tp -> String showF x = withShow (Proxy :: Proxy f) (Proxy :: Proxy tp) (show x) - showsF :: forall tp . f tp -> String -> String- showsF x = withShow (Proxy :: Proxy f) (Proxy :: Proxy tp) (shows x)+ -- | Like 'showsPrec', the precedence argument is /one more/ than the+ -- precedence of the enclosing context.+ showsPrecF :: forall tp. Int -> f tp -> String -> String+ showsPrecF p x = withShow (Proxy :: Proxy f) (Proxy :: Proxy tp) (showsPrec p x)++showsF :: ShowF f => f tp -> String -> String+showsF x = showsPrecF 0 x instance Show x => ShowF (Const x)
src/Data/Parameterized/Context.hs view
@@ -33,60 +33,102 @@ module Data.Parameterized.Context ( #ifdef UNSAFE_OPS- module Data.Parameterized.Context.Unsafe+ module Data.Parameterized.Context.Unsafe #else- module Data.Parameterized.Context.Safe+ module Data.Parameterized.Context.Safe #endif- , singleton- , toVector- , pattern (:>)- , pattern Empty- -- * Context extension and embedding utilities- , CtxEmbedding(..)- , ExtendContext(..)- , ExtendContext'(..)- , ApplyEmbedding(..)- , ApplyEmbedding'(..)- , identityEmbedding- , extendEmbeddingRightDiff- , extendEmbeddingRight- , extendEmbeddingBoth- , ctxeSize- , ctxeAssignment-- -- * Static indexing and lenses for assignments- , Idx- , getCtx- , setCtx- , field- , natIndex- , natIndexProxy-- -- * Currying and uncurrying for assignments- , CurryAssignment- , CurryAssignmentClass(..)- ) where--import Prelude hiding (null)+ , singleton+ , toVector+ , pattern (:>)+ , pattern Empty+ , decompose+ , Data.Parameterized.Context.null+ , Data.Parameterized.Context.init+ , Data.Parameterized.Context.last+ , Data.Parameterized.Context.view+ , forIndexM+ , generateSome+ , generateSomeM+ , fromList+ -- * Context extension and embedding utilities+ , CtxEmbedding(..)+ , ExtendContext(..)+ , ExtendContext'(..)+ , ApplyEmbedding(..)+ , ApplyEmbedding'(..)+ , identityEmbedding+ , extendEmbeddingRightDiff+ , extendEmbeddingRight+ , extendEmbeddingBoth+ , ctxeSize+ , ctxeAssignment -import GHC.TypeLits (Nat, type (-))+ -- * Static indexing and lenses for assignments+ , Idx+ , field+ , natIndex+ , natIndexProxy+ -- * Currying and uncurrying for assignments+ , CurryAssignment+ , CurryAssignmentClass(..)+ -- * Size and Index values+ , size1, size2, size3, size4, size5, size6+ , i1of2, i2of2+ , i1of3, i2of3, i3of3+ , i1of4, i2of4, i3of4, i4of4+ , i1of5, i2of5, i3of5, i4of5, i5of5+ , i1of6, i2of6, i3of6, i4of6, i5of6, i6of6+ ) where -import Control.Lens hiding (Index, view, (:>), Empty)+import Control.Lens hiding (Index, (:>), Empty) import qualified Data.Vector as V import qualified Data.Vector.Mutable as MV+import GHC.TypeLits (Nat, type (-)) +import Data.Parameterized.Classes+import Data.Parameterized.Some+import Data.Parameterized.TraversableFC+ #ifdef UNSAFE_OPS-import Data.Parameterized.Context.Unsafe+import Data.Parameterized.Context.Unsafe #else-import Data.Parameterized.Context.Safe+import Data.Parameterized.Context.Safe #endif -import Data.Parameterized.TraversableFC -- | Create a single element context. singleton :: f tp -> Assignment f (EmptyCtx ::> tp) singleton = (empty :>) +-- |'forIndexM sz f' calls 'f' on indices '[0..sz-1]'.+forIndexM :: forall ctx m+ . Applicative m+ => Size ctx+ -> (forall tp . Index ctx tp -> m ())+ -> m ()+forIndexM sz f = forIndexRange 0 sz (\i r -> f i *> r) (pure ())++-- | Generate an assignment with some context type that is not known.+generateSome :: forall f+ . Int+ -> (Int -> Some f)+ -> Some (Assignment f)+generateSome n f = go n+ where go :: Int -> Some (Assignment f)+ go 0 = Some empty+ go i = (\(Some a) (Some e) -> Some (a `extend` e)) (go (i-1)) (f (i-1))++-- | Generate an assignment with some context type that is not known.+generateSomeM :: forall m f+ . Applicative m+ => Int+ -> (Int -> m (Some f))+ -> m (Some (Assignment f))+generateSomeM n f = go n+ where go :: Int -> m (Some (Assignment f))+ go 0 = pure (Some empty)+ go i = (\(Some a) (Some e) -> Some (a `extend` e)) <$> go (i-1) <*> f (i-1)+ -- | Convert the assignment to a vector. toVector :: Assignment f tps -> (forall tp . f tp -> e) -> V.Vector e toVector a f = V.create $ do@@ -97,6 +139,56 @@ {-# INLINABLE toVector #-} --------------------------------------------------------------------------------+-- Patterns++-- | Pattern synonym for the empty assignment+pattern Empty :: () => ctx ~ EmptyCtx => Assignment f ctx+pattern Empty <- (viewAssign -> AssignEmpty)+ where Empty = empty++infixl :>++-- | Pattern synonym for extending an assignment on the right+pattern (:>) :: () => ctx' ~ (ctx ::> tp) => Assignment f ctx -> f tp -> Assignment f ctx'+pattern (:>) a v <- (viewAssign -> AssignExtend a v)+ where a :> v = extend a v++-- The COMPLETE pragma was not defined until ghc 8.2.*+#if MIN_VERSION_base(4,10,0)+{-# COMPLETE (:>), Empty :: Assignment #-}+#endif++--------------------------------------------------------------------------------+-- | Views++-- | Return true if assignment is empty.+null :: Assignment f ctx -> Bool+null a =+ case viewAssign a of+ AssignEmpty -> True+ AssignExtend{} -> False++decompose :: Assignment f (ctx ::> tp) -> (Assignment f ctx, f tp)+decompose x = (Data.Parameterized.Context.init x, Data.Parameterized.Context.last x)++-- | Return assignment with all but the last block.+init :: Assignment f (ctx '::> tp) -> Assignment f ctx+init x =+ case viewAssign x of+ AssignExtend t _ -> t++-- | Return the last element in the assignment.+last :: Assignment f (ctx '::> tp) -> f tp+last x =+ case viewAssign x of+ AssignExtend _ e -> e++{-# DEPRECATED view "Use viewAssign or the Empty and :> patterns instead." #-}+-- | View an assignment as either empty or an assignment with one appended.+view :: forall f ctx . Assignment f ctx -> AssignView f ctx+view = viewAssign++-------------------------------------------------------------------------------- -- | Context embedding. -- This datastructure contains a proof that the first context is@@ -169,38 +261,13 @@ updated :: CtxEmbedding ctx (ctx' ::> tp) updated = extendEmbeddingRight ctxe --- | Pattern synonym for the empty assignment-pattern Empty :: () => ctx ~ EmptyCtx => Assignment f ctx-pattern Empty <- (view -> AssignEmpty)- where Empty = empty--infixl :>---- | Pattern synonym for extending an assignment on the right-pattern (:>) :: () => ctx' ~ (ctx ::> tp) => Assignment f ctx -> f tp -> Assignment f ctx'-pattern (:>) a v <- (view -> AssignExtend a v)- where a :> v = extend a v---- The COMPLETE pragma was not defined until ghc 8.2.*-#if MIN_VERSION_base(4,10,0)-{-# COMPLETE (:>), Empty :: Assignment #-}-#endif- -------------------------------------------------------------------------------- -- Static indexing based on type-level naturals --- | Get an element from an 'Assignment' by zero-based, left-to-right position.--- The position must be specified using @TypeApplications@ for the @n@ parameter.-getCtx :: forall n ctx f r. Idx n ctx r => Assignment f ctx -> f r-getCtx asgn = asgn ! natIndex @n--setCtx :: forall n ctx f r. Idx n ctx r => f r -> Assignment f ctx -> Assignment f ctx-setCtx = update (natIndex @n)- -- | Get a lens for an position in an 'Assignment' by zero-based, left-to-right position. -- The position must be specified using @TypeApplications@ for the @n@ parameter. field :: forall n ctx f r. Idx n ctx r => Lens' (Assignment f ctx) (f r)-field f = adjustM f (natIndex @n)+field = ixF' (natIndex @n) -- | Constraint synonym used for getting an 'Index' into a 'Ctx'. -- @n@ is the zero-based, left-counted index into the list of types@@ -234,7 +301,7 @@ instance {-# Overlaps #-} (KnownContext xs, Idx' (n-1) xs r) => Idx' n (xs '::> x) r where - natIndex' = skip (natIndex' @_ @(n-1))+ natIndex' = skipIndex (natIndex' @_ @(n-1)) --------------------------------------------------------------------------------@@ -270,5 +337,93 @@ instance CurryAssignmentClass ctx => CurryAssignmentClass (ctx ::> a) where curryAssignment k = curryAssignment (\asgn a -> k (asgn :> a)) uncurryAssignment k asgn =- case view asgn of+ case viewAssign asgn of AssignExtend asgn' x -> uncurryAssignment k asgn' x++-- | Create an assignment from a list of values.+fromList :: [Some f] -> Some (Assignment f)+fromList = go empty+ where go :: Assignment f ctx -> [Some f] -> Some (Assignment f)+ go prev [] = Some prev+ go prev (Some g:next) = (go $! prev `extend` g) next++--------------------------------------------------------------------------------+-- Size and Index values++size1 :: Size (EmptyCtx ::> a)+size1 = incSize zeroSize++size2 :: Size (EmptyCtx ::> a ::> b)+size2 = incSize size1++size3 :: Size (EmptyCtx ::> a ::> b ::> c)+size3 = incSize size2++size4 :: Size (EmptyCtx ::> a ::> b ::> c ::> d)+size4 = incSize size3++size5 :: Size (EmptyCtx ::> a ::> b ::> c ::> d ::> e)+size5 = incSize size4++size6 :: Size (EmptyCtx ::> a ::> b ::> c ::> d ::> e ::> f)+size6 = incSize size5++i1of2 :: Index (EmptyCtx ::> a ::> b) a+i1of2 = skipIndex baseIndex++i2of2 :: Index (EmptyCtx ::> a ::> b) b+i2of2 = nextIndex size1++i1of3 :: Index (EmptyCtx ::> a ::> b ::> c) a+i1of3 = skipIndex i1of2++i2of3 :: Index (EmptyCtx ::> a ::> b ::> c) b+i2of3 = skipIndex i2of2++i3of3 :: Index (EmptyCtx ::> a ::> b ::> c) c+i3of3 = nextIndex size2++i1of4 :: Index (EmptyCtx ::> a ::> b ::> c ::> d) a+i1of4 = skipIndex i1of3++i2of4 :: Index (EmptyCtx ::> a ::> b ::> c ::> d) b+i2of4 = skipIndex i2of3++i3of4 :: Index (EmptyCtx ::> a ::> b ::> c ::> d) c+i3of4 = skipIndex i3of3++i4of4 :: Index (EmptyCtx ::> a ::> b ::> c ::> d) d+i4of4 = nextIndex size3++i1of5 :: Index (EmptyCtx ::> a ::> b ::> c ::> d ::> e) a+i1of5 = skipIndex i1of4++i2of5 :: Index (EmptyCtx ::> a ::> b ::> c ::> d ::> e) b+i2of5 = skipIndex i2of4++i3of5 :: Index (EmptyCtx ::> a ::> b ::> c ::> d ::> e) c+i3of5 = skipIndex i3of4++i4of5 :: Index (EmptyCtx ::> a ::> b ::> c ::> d ::> e) d+i4of5 = skipIndex i4of4++i5of5 :: Index (EmptyCtx ::> a ::> b ::> c ::> d ::> e) e+i5of5 = nextIndex size4++i1of6 :: Index (EmptyCtx ::> a ::> b ::> c ::> d ::> e ::> f) a+i1of6 = skipIndex i1of5++i2of6 :: Index (EmptyCtx ::> a ::> b ::> c ::> d ::> e ::> f) b+i2of6 = skipIndex i2of5++i3of6 :: Index (EmptyCtx ::> a ::> b ::> c ::> d ::> e ::> f) c+i3of6 = skipIndex i3of5++i4of6 :: Index (EmptyCtx ::> a ::> b ::> c ::> d ::> e ::> f) d+i4of6 = skipIndex i4of5++i5of6 :: Index (EmptyCtx ::> a ::> b ::> c ::> d ::> e ::> f) e+i5of6 = skipIndex i5of5++i6of6 :: Index (EmptyCtx ::> a ::> b ::> c ::> d ::> e ::> f) f+i6of6 = nextIndex size5
src/Data/Parameterized/Context/Safe.hs view
@@ -24,6 +24,7 @@ -- 'Data.Coerce.coerce' to understand indexes in a new context without -- actually breaking things. --------------------------------------------------------------------------+{-# LANGUAGE RoleAnnotations #-} {-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE ExistentialQuantification #-}@@ -39,9 +40,12 @@ {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeInType #-} {-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeInType #-} module Data.Parameterized.Context.Safe ( module Data.Parameterized.Ctx+ -- * Size , Size , sizeInt , zeroSize@@ -56,39 +60,36 @@ , Diff , noDiff , extendRight- , KnownDiff(..) , DiffView(..) , viewDiff+ , KnownDiff(..) -- * Indexing , Index , indexVal- , base- , skip+ , baseIndex+ , skipIndex , lastIndex , nextIndex , extendIndex , extendIndex' , forIndex+ , forIndexRange , intIndex -- * Assignments , Assignment , size- , replicate+ , Data.Parameterized.Context.Safe.replicate , generate , generateM , empty- , null , extend- , update , adjust+ , update , adjustM- , init , AssignView(..)- , view- , decompose+ , viewAssign , (!) , (!^)- , toList , zipWith , zipWithM , (<++>)@@ -104,6 +105,7 @@ import Data.Maybe (listToMaybe) import Data.Type.Equality import Prelude hiding (init, map, null, replicate, succ, zipWith)+import Data.Kind(Type) #if !MIN_VERSION_base(4,8,0) import Data.Functor@@ -121,7 +123,7 @@ -- | An indexed singleton type representing the size of a context. data Size (ctx :: Ctx k) where SizeZero :: Size 'EmptyCtx- SizeSucc :: Size ctx -> Size (ctx '::> tp)+ SizeSucc :: !(Size ctx) -> Size (ctx '::> tp) -- | Convert a context size to an 'Int'. sizeInt :: Size ctx -> Int@@ -225,7 +227,7 @@ -- context. data Index (ctx :: Ctx k) (tp :: k) where IndexHere :: Size ctx -> Index (ctx '::> tp) tp- IndexThere :: Index ctx tp -> Index (ctx '::> tp') tp+ IndexThere :: !(Index ctx tp) -> Index (ctx '::> tp') tp -- | Convert an index to an 'Int', where the index of the left-most type in the context is 0. indexVal :: Index ctx tp -> Int@@ -254,12 +256,12 @@ compareF (IndexThere idx1) (IndexThere idx2) = lexCompareF idx1 idx2 $ EQF -- | Index for first element in context.-base :: Index ('EmptyCtx '::> tp) tp-base = IndexHere SizeZero+baseIndex :: Index ('EmptyCtx '::> tp) tp+baseIndex = IndexHere SizeZero -- | Increase context while staying at same index.-skip :: Index ctx x -> Index (ctx '::> y) x-skip idx = IndexThere idx+skipIndex :: Index ctx x -> Index (ctx '::> y) x+skipIndex idx = IndexThere idx -- | Return the index of an element one past the size. nextIndex :: Size ctx -> Index (ctx '::> tp) tp@@ -291,7 +293,44 @@ go _ SizeZero = id go g (SizeSucc sz) = \r -> go (\i -> g (IndexThere i)) sz $ f r (g (IndexHere sz)) +data LDiff (l :: Ctx k) (r :: Ctx k) where+ LDiffHere :: LDiff a a+ LDiffThere :: !(LDiff (a::>x) b) -> LDiff a b +ldiffIndex :: Index a tp -> LDiff a b -> Index b tp+ldiffIndex i LDiffHere = i+ldiffIndex i (LDiffThere d) = ldiffIndex (IndexThere i) d++forIndexLDiff :: Size a+ -> LDiff a b+ -> (forall tp . Index b tp -> r -> r)+ -> r+ -> r+forIndexLDiff _ LDiffHere _ r = r+forIndexLDiff sz (LDiffThere d) f r =+ forIndexLDiff (SizeSucc sz) d f (f (ldiffIndex (IndexHere sz) d) r)++forIndexRangeImpl :: Int+ -> Size a+ -> LDiff a b+ -> (forall tp . Index b tp -> r -> r)+ -> r+ -> r+forIndexRangeImpl 0 sz d f r = forIndexLDiff sz d f r+forIndexRangeImpl _ SizeZero _ _ r = r+forIndexRangeImpl i (SizeSucc sz) d f r =+ forIndexRangeImpl (i-1) sz (LDiffThere d) f r++-- | Given an index 'i', size 'n', a function 'f', value 'v', and a function 'f',+-- 'forIndex i n f v' is equivalent to 'v' when 'i >= sizeInt n', and+-- 'f i (forIndexRange (i+1) n v0)' otherwise.+forIndexRange :: Int+ -> Size ctx+ -> (forall tp . Index ctx tp -> r -> r)+ -> r+ -> r+forIndexRange i sz f r = forIndexRangeImpl i sz LDiffHere f r+ indexList :: forall ctx. Size ctx -> [Some (Index ctx)] indexList sz_top = go id [] sz_top where go :: (forall tp. Index ctx' tp -> Index ctx tp)@@ -315,21 +354,18 @@ -- | An assignment is a sequence that maps each index with type 'tp' to -- a value of type 'f tp'.-data Assignment (f :: k -> *) (ctx :: Ctx k) where+data Assignment (f :: k -> Type) (ctx :: Ctx k) where AssignmentEmpty :: Assignment f EmptyCtx AssignmentExtend :: Assignment f ctx -> f tp -> Assignment f (ctx ::> tp) -- | View an assignment as either empty or an assignment with one appended.-data AssignView (f :: k -> *) (ctx :: Ctx k) where+data AssignView (f :: k -> Type) (ctx :: Ctx k) where AssignEmpty :: AssignView f EmptyCtx AssignExtend :: Assignment f ctx -> f tp -> AssignView f (ctx::>tp) -view :: forall f ctx . Assignment f ctx -> AssignView f ctx-view AssignmentEmpty = AssignEmpty-view (AssignmentExtend asgn x) = AssignExtend asgn x--decompose :: Assignment f (ctx ::> tp) -> (Assignment f ctx, f tp)-decompose (AssignmentExtend a v) = (a,v)+viewAssign :: forall f ctx . Assignment f ctx -> AssignView f ctx+viewAssign AssignmentEmpty = AssignEmpty+viewAssign (AssignmentExtend asgn x) = AssignExtend asgn x instance NFData (Assignment f ctx) where rnf AssignmentEmpty = ()@@ -377,20 +413,17 @@ empty :: Assignment f 'EmptyCtx empty = AssignmentEmpty --- | Return true if assignment is empty.-null :: Assignment f ctx -> Bool-null AssignmentEmpty = True-null _ = False- extend :: Assignment f ctx -> f tp -> Assignment f (ctx '::> tp) extend asgn e = AssignmentExtend asgn e -update :: Index ctx tp -> f tp -> Assignment f ctx -> Assignment f ctx-update idx e asgn = adjust (\_ -> e) idx asgn-+{-# DEPRECATED adjust "Replace 'adjust f i asgn' with 'Lens.over (ixF i) f asgn' instead." #-} adjust :: forall f ctx tp. (f tp -> f tp) -> Index ctx tp -> Assignment f ctx -> Assignment f ctx-adjust f idx m = runIdentity (adjustM (Identity . f) idx m)+adjust f idx asgn = runIdentity (adjustM (Identity . f) idx asgn) +{-# DEPRECATED update "Replace 'update idx val asgn' with 'Lens.set (ixF idx) val asgn' instead." #-}+update :: forall f ctx tp. Index ctx tp -> f tp -> Assignment f ctx -> Assignment f ctx+update i v a = adjust (\_ -> v) i a+ adjustM :: forall m f ctx tp. Functor m => (f tp -> m (f tp)) -> Index ctx tp -> Assignment f ctx -> m (Assignment f ctx) adjustM f = go (\x -> x) where@@ -404,22 +437,17 @@ go _ _ _ = error "SafeTypeContext.adjustM: impossible!" #endif -type instance IndexF (Assignment (f :: k -> *) ctx) = Index ctx-type instance IxValueF (Assignment (f :: k -> *) ctx) = f+type instance IndexF (Assignment (f :: k -> Type) ctx) = Index ctx+type instance IxValueF (Assignment (f :: k -> Type) ctx) = f -instance forall (f :: k -> *) ctx. IxedF k (Assignment f ctx) where+instance forall (f :: k -> Type) ctx. IxedF k (Assignment f ctx) where ixF :: Index ctx x -> Lens.Lens' (Assignment f ctx) (f x) ixF idx f = adjustM f idx -instance forall (f :: k -> *) ctx. IxedF' k (Assignment f ctx) where+instance forall (f :: k -> Type) ctx. IxedF' k (Assignment f ctx) where ixF' :: Index ctx x -> Lens.Lens' (Assignment f ctx) (f x) ixF' idx f = adjustM f idx ---- | Return assignment with all but the last block.-init :: Assignment f (ctx '::> tp) -> Assignment f ctx-init (AssignmentExtend asgn _) = asgn- idxlookup :: (forall tp. a tp -> b tp) -> Assignment a ctx -> forall tp. Index ctx tp -> b tp idxlookup f (AssignmentExtend _ x) (IndexHere _) = f x idxlookup f (AssignmentExtend ctx _) (IndexThere idx) = idxlookup f ctx idx@@ -511,7 +539,7 @@ map :: (forall tp . f tp -> g tp) -> Assignment f c -> Assignment g c map = fmapFC -traverseF :: forall (f:: k -> *) (g::k -> *) (m:: * -> *) (c::Ctx k)+traverseF :: forall (f:: k -> Type) (g::k -> Type) (m:: Type -> Type) (c::Ctx k) . Applicative m => (forall tp . f tp -> m (g tp)) -> Assignment f c@@ -572,7 +600,7 @@ type MyZ = 'MyZ type MyS = 'MyS -data MyNatRepr :: MyNat -> * where+data MyNatRepr :: MyNat -> Type where MyZR :: MyNatRepr MyZ MySR :: MyNatRepr n -> MyNatRepr (MyS n) @@ -581,7 +609,7 @@ StrongCtxUpdate MyZ (ctx::>x) z = ctx ::> z StrongCtxUpdate (MyS n) (ctx::>x) z = (StrongCtxUpdate n ctx z) ::> x -type family MyNatLookup (n::MyNat) (ctx::Ctx k) (f::k -> *) :: * where+type family MyNatLookup (n::MyNat) (ctx::Ctx k) (f::k -> Type) :: Type where MyNatLookup n EmptyCtx f = () MyNatLookup MyZ (ctx::>x) f = f x MyNatLookup (MyS n) (ctx::>x) f = MyNatLookup n ctx f
src/Data/Parameterized/Context/Unsafe.hs view
@@ -12,9 +12,13 @@ {-# LANGUAGE Trustworthy #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeInType #-} {-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE TypeInType #-} module Data.Parameterized.Context.Unsafe ( module Data.Parameterized.Ctx+ , KnownContext(..)+ -- * Size , Size , sizeInt , zeroSize@@ -24,26 +28,24 @@ , addSize , SizeView(..) , viewSize- , KnownContext(..) -- * Diff , Diff , noDiff , extendRight- , KnownDiff(..) , DiffView(..) , viewDiff+ , KnownDiff(..) -- * Indexing , Index , indexVal- , base- , skip+ , baseIndex+ , skipIndex , lastIndex , nextIndex , extendIndex , extendIndex' , forIndex , forIndexRange- , forIndexM , intIndex -- ** IndexRange , IndexRange@@ -54,32 +56,24 @@ -- * Assignments , Assignment , size- , replicate+ , Data.Parameterized.Context.Unsafe.replicate , generate , generateM- , generateSome- , generateSomeM , empty- , null , extend- , update , adjust+ , update , adjustM- , init- , last , AssignView(..)- , view- , decompose- , fromList+ , viewAssign , (!) , (!^)- , zipWith+ , Data.Parameterized.Context.Unsafe.zipWith , zipWithM , (<++>) , traverseWithIndex ) where -import Control.Applicative hiding (empty) import qualified Control.Category as Cat import Control.DeepSeq import Control.Exception@@ -91,9 +85,7 @@ import Data.List (intercalate) import Data.Proxy import Unsafe.Coerce--import Prelude hiding (init, last, map, null, replicate, succ, zipWith, (++))-import qualified Prelude+import Data.Kind(Type) import Data.Parameterized.Classes import Data.Parameterized.Ctx@@ -105,8 +97,14 @@ -- Size -- | Represents the size of a context.-newtype Size (ctx :: Ctx k) = Size { sizeInt :: Int }+newtype Size (ctx :: Ctx k) = Size Int +type role Size nominal++-- | Convert a context size to an 'Int'.+sizeInt :: Size ctx -> Int+sizeInt (Size n) = n+ -- | The size of an empty context. zeroSize :: Size 'EmptyCtx zeroSize = Size 0@@ -199,6 +197,8 @@ -- context. newtype Index (ctx :: Ctx k) (tp :: k) = Index { indexVal :: Int } +type role Index nominal nominal+ instance Eq (Index ctx tp) where Index i == Index j = i == j @@ -217,12 +217,12 @@ | otherwise = GTF -- | Index for first element in context.-base :: Index ('EmptyCtx '::> tp) tp-base = Index 0+baseIndex :: Index ('EmptyCtx '::> tp) tp+baseIndex = Index 0 -- | Increase context while staying at same index.-skip :: Index ctx x -> Index (ctx '::> y) x-skip (Index i) = Index i+skipIndex :: Index ctx x -> Index (ctx '::> y) x+skipIndex (Index i) = Index i -- | Return the index of a element one past the size. nextIndex :: Size ctx -> Index (ctx ::> tp) tp@@ -265,14 +265,6 @@ | i >= n = r | otherwise = f (Index i) (forIndexRange (i+1) (Size n) f r) --- |'forIndexM sz f' calls 'f' on indices '[0..sz-1]'.-forIndexM :: forall ctx m- . Applicative m- => Size ctx- -> (forall tp . Index ctx tp -> m ())- -> m ()-forIndexM sz f = forIndexRange 0 sz (\i r -> f i *> r) (pure ())- -- | Return index at given integer or nothing if integer is out of bounds. intIndex :: Int -> Size ctx -> Maybe (Some (Index ctx)) intIndex i n | 0 <= i && i < sizeInt n = Just (Some (Index i))@@ -323,7 +315,7 @@ -- -- The first parameter is the height of the tree. -- The second is the parameterized value.-data BalancedTree h (f :: k -> *) (p :: Ctx k) where+data BalancedTree h (f :: k -> Type) (p :: Ctx k) where BalLeaf :: !(f x) -> BalancedTree 'Zero f (SingleCtx x) BalPair :: !(BalancedTree h f x) -> !(BalancedTree h f y)@@ -474,7 +466,7 @@ ------------------------------------------------------------------------ -- BinomialTree -data BinomialTree (h::Height) (f :: k -> *) :: Ctx k -> * where+data BinomialTree (h::Height) (f :: k -> Type) :: Ctx k -> Type where Empty :: BinomialTree h f EmptyCtx -- Contains size of the subtree, subtree, then element.@@ -607,18 +599,11 @@ ------------------------------------------------------------------------ -- Dropping -type family InitCtx (x :: Ctx k) :: Ctx k-type instance InitCtx (x ::> y) = x--type family LastCtx (x :: Ctx k) :: k-type instance LastCtx (x ::> y) = y---- data DropResult f (ctx :: Ctx k) where DropEmpty :: DropResult f EmptyCtx- DropExt :: BinomialTree 'Zero f (InitCtx ctx)- -> f (LastCtx ctx)- -> DropResult f ctx+ DropExt :: BinomialTree 'Zero f x+ -> f y+ -> DropResult f (x ::> y) -- | 'bal_drop x y' returns the tree formed 'append x (init y)' bal_drop :: forall h f x y@@ -703,13 +688,17 @@ ------------------------------------------------------------------------ -- Assignment -type role Assignment representational nominal- -- | An assignment is a sequence that maps each index with type 'tp' to -- a value of type 'f tp'.-newtype Assignment (f :: k -> *) (ctx :: Ctx k)+--+-- This assignment implementation uses a binomial tree implementation+-- that offers lookups and updates in time and space logarithmic with+-- respect to the number of elements in the context.+newtype Assignment (f :: k -> Type) (ctx :: Ctx k) = Assignment (BinomialTree 'Zero f ctx) +type role Assignment nominal nominal+ instance NFData (Assignment f ctx) where rnf a = seq a () @@ -717,27 +706,6 @@ size :: Assignment f ctx -> Size ctx size (Assignment t) = Size (tsize t) --- | Generate an assignment with some context type that is not known.-generateSome :: forall f- . Int- -> (Int -> Some f)- -> Some (Assignment f)-generateSome n f = go n- where go :: Int -> Some (Assignment f)- go 0 = Some empty- go i = (\(Some a) (Some e) -> Some (a `extend` e)) (go (i-1)) (f (i-1))---- | Generate an assignment with some context type that is not known.-generateSomeM :: forall m f- . Applicative m- => Int- -> (Int -> m (Some f))- -> m (Some (Assignment f))-generateSomeM n f = go n- where go :: Int -> m (Some (Assignment f))- go 0 = pure (Some empty)- go i = (\(Some a) (Some e) -> Some (a `extend` e)) <$> go (i-1) <*> f (i-1)- -- | @replicate n@ make a context with different copies of the same -- polymorphic value. replicate :: Size ctx -> (forall tp . f tp) -> Assignment f ctx@@ -763,11 +731,6 @@ empty :: Assignment f EmptyCtx empty = Assignment Empty --- | Return true if assignment is empty.-null :: Assignment f ctx -> Bool-null (Assignment Empty) = True-null (Assignment _) = False- extend :: Assignment f ctx -> f x -> Assignment f (ctx ::> x) extend (Assignment x) y = Assignment $ append x (BalLeaf y) @@ -823,6 +786,14 @@ instance ShowF f => ShowF (Assignment f) +{-# DEPRECATED adjust "Replace 'adjust f i asgn' with 'Lens.over (ixF i) f asgn' instead." #-}+adjust :: (f tp -> f tp) -> Index ctx tp -> Assignment f ctx -> Assignment f ctx+adjust f idx asgn = runIdentity (adjustM (Identity . f) idx asgn)++{-# DEPRECATED update "Replace 'update idx val asgn' with 'Lens.set (ixF idx) val asgn' instead." #-}+update :: Index ctx tp -> f tp -> Assignment f ctx -> Assignment f ctx+update i v a = adjust (\_ -> v) i a+ -- | Modify the value of an assignment at a particular index. adjustM :: Functor m => (f tp -> m (f tp)) -> Index ctx tp -> Assignment f ctx -> m (Assignment f ctx) adjustM f (Index i) (Assignment a) = Assignment <$> (unsafe_bin_adjust f a i 0)@@ -831,22 +802,12 @@ type instance IndexF (Assignment f ctx) = Index ctx type instance IxValueF (Assignment f ctx) = f -instance forall (f :: k -> *) ctx. IxedF k (Assignment f ctx) where- ixF :: Index ctx x -> Lens.Lens' (Assignment f ctx) (f x)- ixF idx f = adjustM f idx--instance forall (f :: k -> *) ctx. IxedF' k (Assignment f ctx) where+instance forall (f :: k -> Type) ctx. IxedF' k (Assignment (f :: k -> Type) ctx) where ixF' :: Index ctx x -> Lens.Lens' (Assignment f ctx) (f x) ixF' idx f = adjustM f idx ---- | Modify the value of an assignment at a particular index.-adjust :: (f tp -> f tp) -> Index ctx tp -> Assignment f ctx -> Assignment f ctx-adjust f idx asgn = runIdentity (adjustM (Identity . f) idx asgn)---- | Update the assignment at a particular index.-update :: Index ctx tp -> f tp -> Assignment f ctx -> Assignment f ctx-update i v a = adjust (\_ -> v) i a+instance forall (f :: k -> Type) ctx. IxedF k (Assignment f ctx) where+ ixF = ixF' -- This is an unsafe version of update that changes the type of the expression. unsafeUpdate :: Int -> Assignment f ctx -> f u -> Assignment f ctx'@@ -860,26 +821,11 @@ -> AssignView f (ctx::>tp) -- | View an assignment as either empty or an assignment with one appended.-view :: forall f ctx . Assignment f ctx -> AssignView f ctx-view (Assignment x) =+viewAssign :: forall f ctx . Assignment f ctx -> AssignView f ctx+viewAssign (Assignment x) = case bin_drop x of DropEmpty -> AssignEmpty- DropExt t v -> unsafeCoerce $ AssignExtend (Assignment (unsafeCoerce t)) v---- | Return assignment with all but the last block.-init :: Assignment f (ctx '::> tp) -> Assignment f ctx-init (Assignment x) =- case bin_drop x of- DropExt t _ -> Assignment t---- | Return the last element in the assignment.-last :: Assignment f (ctx '::> tp) -> f tp-last x =- case view x of- AssignExtend _ e -> e--decompose :: Assignment f (ctx ::> tp) -> (Assignment f ctx, f tp)-decompose x = case view x of AssignExtend a v -> (a,v)+ DropExt t v -> AssignExtend (Assignment t) v zipWith :: (forall x . f x -> g x -> h x) -> Assignment f a@@ -913,13 +859,6 @@ -> Assignment f ctx -> m (Assignment g ctx) traverseWithIndex f a = generateM (size a) $ \i -> f i (a ! i)---- | Create an assignment from a list of values.-fromList :: [Some f] -> Some (Assignment f)-fromList = go empty- where go :: Assignment f ctx -> [Some f] -> Some (Assignment f)- go prev [] = Some prev- go prev (Some g:next) = (go $! prev `extend` g) next ------------------------------------------------------------------------ -- Appending
src/Data/Parameterized/List.hs view
@@ -29,6 +29,7 @@ , indexed , imap , ifoldr+ , izipWith , itraverse -- * Constants , index0@@ -51,8 +52,13 @@ infixr 5 :< instance ShowF f => Show (List f sh) where- show Nil = "Nil"- show (elt :< rest) = showF elt ++ " :< " ++ show rest+ showsPrec _ Nil = showString "Nil"+ showsPrec p (elt :< rest) = showParen (p > precCons) $+ -- Unlike a derived 'Show' instance, we don't print parens implied+ -- by right associativity.+ showsPrecF (precCons+1) elt . showString " :< " . showsPrec 0 rest+ where+ precCons = 5 instance ShowF f => ShowF (List f) @@ -202,6 +208,24 @@ case ops of Nil -> b a :< rest -> f (g IndexHere) a (go (\ix -> g (IndexThere ix)) rest b)++-- | Zip up two lists with a zipper function, which can use the index.+izipWith :: forall a b c sh . (forall tp. Index sh tp -> a tp -> b tp -> c tp)+ -> List a sh+ -> List b sh+ -> List c sh+izipWith f = go id+ where+ go :: forall sh' .+ (forall tp . Index sh' tp -> Index sh tp)+ -> List a sh'+ -> List b sh'+ -> List c sh'+ go g as bs =+ case (as, bs) of+ (Nil, Nil) -> Nil+ (a :< as', b :< bs') ->+ f (g IndexHere) a b :< go (g . IndexThere) as' bs' -- | Traverse with an additional index. itraverse :: forall a b sh t
src/Data/Parameterized/Map.hs view
@@ -21,6 +21,7 @@ {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE Trustworthy #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeInType #-} module Data.Parameterized.Map ( MapF -- * Construction@@ -69,6 +70,7 @@ import Control.Monad.Identity import Data.List (intercalate, foldl') import Data.Maybe ()+import Data.Kind(Type) import Data.Parameterized.Classes import Data.Parameterized.Some@@ -105,7 +107,7 @@ -- MapF -- | A map from parameterized keys to values with the same paramter type.-data MapF (k :: v -> *) (a :: v -> *) where+data MapF (k :: v -> Type) (a :: v -> Type) where Bin :: {-# UNPACK #-} !Size -- Number of elements in tree. -> !(k x)@@ -205,12 +207,12 @@ type instance IxValueF (MapF k v) = v -- | Turn a map key into a traversal that visits the indicated element in the map, if it exists.-instance forall (k:: a -> *) v. OrdF k => IxedF a (MapF k v) where+instance forall (k:: a -> Type) v. OrdF k => IxedF a (MapF k v) where ixF :: k x -> Traversal' (MapF k v) (v x) ixF i f m = updatedValue <$> updateAtKey i (pure Nothing) (\x -> Set <$> f x) m -- | Turn a map key into a lens that points into the indicated position in the map.-instance forall (k:: a -> *) v. OrdF k => AtF a (MapF k v) where+instance forall (k:: a -> Type) v. OrdF k => AtF a (MapF k v) where atF :: k x -> Lens' (MapF k v) (Maybe (v x)) atF i f m = updatedValue <$> updateAtKey i (f Nothing) (\x -> maybe Delete Set <$> f (Just x)) m @@ -425,7 +427,7 @@ -- | Generate a map from a foldable collection of keys and a -- function from keys to values.-fromKeys :: forall m (t :: * -> *) (a :: k -> *) (v :: k -> *)+fromKeys :: forall m (t :: Type -> Type) (a :: k -> Type) (v :: k -> Type) . (Monad m, Foldable t, OrdF a) => (forall tp . a tp -> m (v tp)) -- ^ Function for evaluating a register value.@@ -438,7 +440,7 @@ -- | Generate a map from a foldable collection of keys and a monadic -- function from keys to values.-fromKeysM :: forall m (t :: * -> *) (a :: k -> *) (v :: k -> *)+fromKeysM :: forall m (t :: Type -> Type) (a :: k -> Type) (v :: k -> Type) . (Monad m, Foldable t, OrdF a) => (forall tp . a tp -> m (v tp)) -- ^ Function for evaluating a register value.
src/Data/Parameterized/NatRepr.hs view
@@ -26,6 +26,7 @@ {-# LANGUAGE RankNTypes #-} {-# LANGUAGE PatternGuards #-} {-# LANGUAGE Trustworthy #-}+{-# LANGUAGE TypeApplications #-} #if MIN_VERSION_base(4,9,0) {-# OPTIONS_GHC -fno-warn-redundant-constraints #-} #endif@@ -43,6 +44,7 @@ , incNat , addNat , subNat+ , divNat , halfNat , withDivModNat , natMultiply@@ -78,16 +80,24 @@ , leqAdd , leqSub , leqMulPos+ , leqAddPos , addIsLeq , withAddLeq , addPrefixIsLeq , withAddPrefixLeq , addIsLeqLeft1 , dblPosIsPos+ , leqMulMono -- * Arithmetic proof , plusComm+ , mulComm , plusMinusCancel+ , minusPlusCancel+ , addMulDistribRight , withAddMulDistribRight+ , withSubMulDistribRight+ , mulCancelR+ , mul2Plus -- * Re-exports typelists basics -- , NatK , type (+)@@ -140,17 +150,17 @@ -- | Result of comparing two numbers. data NatComparison m n where -- First number is less than second.- NatLT :: !(NatRepr y) -> NatComparison x (x+(y+1))+ NatLT :: x+1 <= x+(y+1) => !(NatRepr y) -> NatComparison x (x+(y+1)) NatEQ :: NatComparison x x -- First number is greater than second.- NatGT :: !(NatRepr y) -> NatComparison (x+(y+1)) x+ NatGT :: x+1 <= x+(y+1) => !(NatRepr y) -> NatComparison (x+(y+1)) x compareNat :: NatRepr m -> NatRepr n -> NatComparison m n compareNat m n = case compare (natValue m) (natValue n) of- LT -> unsafeCoerce $ NatLT (NatRepr (natValue n - natValue m - 1))- EQ -> unsafeCoerce $ NatEQ- GT -> unsafeCoerce $ NatGT (NatRepr (natValue m - natValue n - 1))+ LT -> unsafeCoerce (NatLT @0 @0) (NatRepr (natValue n - natValue m - 1))+ EQ -> unsafeCoerce NatEQ+ GT -> unsafeCoerce (NatGT @0 @0) (NatRepr (natValue m - natValue n - 1)) instance OrdF NatRepr where compareF x y =@@ -215,6 +225,9 @@ subNat :: (n <= m) => NatRepr m -> NatRepr n -> NatRepr (m-n) subNat (NatRepr m) (NatRepr n) = NatRepr (m-n) +divNat :: (1 <= n) => NatRepr (m * n) -> NatRepr n -> NatRepr m+divNat (NatRepr x) (NatRepr y) = NatRepr (div x y)+ withDivModNat :: forall n m a. NatRepr n -> NatRepr m@@ -264,7 +277,7 @@ where i = i0 .&. maxUnsigned w -- | @unsignedClamp w i@ rounds @i@ to the nearest value between--- @0@ and @2^w-i@ (inclusive).+-- @0@ and @2^w-1@ (inclusive). unsignedClamp :: NatRepr w -> Integer -> Integer unsignedClamp w i | i < minUnsigned w = minUnsigned w@@ -272,7 +285,7 @@ | otherwise = i -- | @signedClamp w i@ rounds @i@ to the nearest value between--- @-2^(w-1)@ and @2^(w-1)-i@ (inclusive).+-- @-2^(w-1)@ and @2^(w-1)-1@ (inclusive). signedClamp :: (1 <= w) => NatRepr w -> Integer -> Integer signedClamp w i | i < minSigned w = minSigned w@@ -299,16 +312,41 @@ plusComm :: forall f m g n . f m -> g n -> m+n :~: n+m plusComm _ _ = unsafeCoerce (Refl :: m+n :~: m+n) +-- | Produce evidence that * is commutative.+mulComm :: forall f m g n. f m -> g n -> (m * n) :~: (n * m)+mulComm _ _ = unsafeCoerce Refl++mul2Plus :: forall f n. f n -> (n + n) :~: (2 * n)+mul2Plus n = case addMulDistribRight (Proxy @1) (Proxy @1) n of+ Refl -> Refl+ -- | Cancel an add followed b a subtract plusMinusCancel :: forall f m g n . f m -> g n -> (m + n) - n :~: m plusMinusCancel _ _ = unsafeCoerce (Refl :: m :~: m) +minusPlusCancel :: forall f m g n . (n <= m) => f m -> g n -> (m - n) + n :~: m+minusPlusCancel _ _ = unsafeCoerce (Refl :: m :~: m)++addMulDistribRight :: forall n m p f g h. f n -> g m -> h p+ -> ((n * p) + (m * p)) :~: ((n + m) * p)+addMulDistribRight _n _m _p = unsafeCoerce Refl+++ withAddMulDistribRight :: forall n m p f g h a. f n -> g m -> h p -> ( (((n * p) + (m * p)) ~ ((n + m) * p)) => a) -> a-withAddMulDistribRight _n _m _p f =+withAddMulDistribRight n m p f =+ case addMulDistribRight n m p of+ Refl -> f++withSubMulDistribRight :: forall n m p f g h a. (m <= n) => f n -> g m -> h p+ -> ( (((n * p) - (m * p)) ~ ((n - m) * p)) => a) -> a+withSubMulDistribRight _n _m _p f = case unsafeCoerce (Refl :: 0 :~: 0) of- (Refl :: (((n * p) + (m * p)) :~: ((n + m) * p)) ) -> f+ (Refl :: (((n * p) - (m * p)) :~: ((n - m) * p)) ) -> f ++ ------------------------------------------------------------------------ -- LeqProof @@ -379,7 +417,7 @@ -- LeqProof combinators -- | Create a leqProof using two proxies-leqProof :: (m <= n) => f m -> f n -> LeqProof m n+leqProof :: (m <= n) => f m -> g n -> LeqProof m n leqProof _ _ = LeqProof withLeqProof :: LeqProof m n -> ((m <= n) => a) -> a@@ -406,11 +444,17 @@ -> LeqProof 1 (x*y) leqMulPos _ _ = leqMulCongr (LeqProof :: LeqProof 1 x) (LeqProof :: LeqProof 1 y) +leqMulMono :: (1 <= x) => p x -> q y -> LeqProof y (x * y)+leqMulMono x y = leqMulCongr (leqProof (Proxy :: Proxy 1) x) (leqRefl y)+ -- | Produce proof that adding a value to the larger element in an LeqProof -- is larger leqAdd :: forall f m n p . LeqProof m n -> f p -> LeqProof m (n+p) leqAdd x _ = leqAdd2 x (LeqProof :: LeqProof 0 p) +leqAddPos :: (1 <= m, 1 <= n) => p m -> q n -> LeqProof 1 (m + n)+leqAddPos m n = leqAdd (leqProof (Proxy :: Proxy 1) m) n+ -- | Produce proof that subtracting a value from the smaller element is smaller. leqSub :: forall m n p . LeqProof m n -> LeqProof p m -> LeqProof (m-p) n leqSub x _ = leqSub2 x (LeqProof :: LeqProof 0 p)@@ -477,3 +521,7 @@ go n' = case isZeroNat n' of ZeroNat -> f0 NonZeroNat -> let n'' = predNat n' in ih n'' (go n'')++mulCancelR ::+ (1 <= c, (n1 * c) ~ (n2 * c)) => f1 n1 -> f2 n2 -> f3 c -> (n1 :~: n2)+mulCancelR _ _ _ = unsafeCoerce Refl
src/Data/Parameterized/TH/GADT.hs view
@@ -14,7 +14,9 @@ {-# LANGUAGE TypeOperators #-} {-# LANGUAGE EmptyCase #-} module Data.Parameterized.TH.GADT- ( structuralEquality+ ( -- * Instance generators+ -- $typePatterns+ structuralEquality , structuralTypeEquality , structuralTypeOrd , structuralTraversal@@ -71,6 +73,9 @@ ------------------------------------------------------------------------ -- TypePat +-- | A type used to describe (and match) types appearing in generated pattern+-- matches inside of the TH generators in this module ('structuralEquality',+-- 'structuralTypeEquality', 'structuralTypeOrd', and 'structuralTraversal') data TypePat = TypeApp TypePat TypePat -- ^ The application of a type. | AnyType -- ^ Match any type.@@ -117,7 +122,7 @@ typeVars = Set.fromList . freeVariables --- | @declareStructuralEquality@ declares a structural equality predicate.+-- | @structuralEquality@ declares a structural equality predicate. structuralEquality :: TypeQ -> [(TypePat,ExpQ)] -> ExpQ structuralEquality tpq pats = [| \x y -> isJust ($(structuralTypeEquality tpq pats) x y) |]@@ -208,7 +213,7 @@ then [| \x -> case x of {} |] else [| \x y -> $(caseE [| x |] (trueEqs [| y |])) |] --- | @structuralTypeEquality f@ returns a function with the type:+-- | @structuralTypeOrd f@ returns a function with the type: -- forall x y . f x -> f y -> OrderingF x y -- -- This implementation avoids matching on both the first and second@@ -441,3 +446,43 @@ matchShowCtor :: ExpQ -> ConstructorInfo -> MatchQ matchShowCtor p con = showCon p (constructorName con) (length (constructorFields con))++-- $typePatterns+--+-- The Template Haskell instance generators 'structuralEquality',+-- 'structuralTypeEquality', 'structuralTypeOrd', and 'structuralTraversal'+-- employ heuristics to generate valid instances in the majority of cases. Most+-- failures in the heuristics occur on sub-terms that are type indexed. To+-- handle cases where these functions fail to produce a valid instance, they+-- take a list of exceptions in the form of their second parameter, which has+-- type @[('TypePat', 'ExpQ')]@. Each 'TypePat' is a /matcher/ that tells the+-- TH generator to use the 'ExpQ' to process the matched sub-term. Consider the+-- following example:+--+-- > data T a b where+-- > C1 :: NatRepr n -> T () n+-- >+-- > instance TestEquality (T a) where+-- > testEquality = $(structuralTypeEquality [t|T|]+-- > [ (ConType [t|NatRepr|] `TypeApp` AnyType, [|testEquality|])+-- > ])+--+-- The exception list says that 'structuralTypeEquality' should use+-- 'testEquality' to compare any sub-terms of type @'NatRepr' n@ in a value of+-- type @T@.+--+-- * 'AnyType' means that the type parameter in that position can be instantiated as any type+--+-- * @'DataArg' n@ means that the type parameter in that position is the @n@-th+-- type parameter of the GADT being traversed (@T@ in the example)+--+-- * 'TypeApp' is type application+--+-- * 'ConType' specifies a base type+--+-- The exception list could have equivalently (and more precisely) have been specified as:+--+-- > [(ConType [t|NatRepr|] `TypeApp` DataArg 1, [|testEquality|])]+--+-- The use of 'DataArg' says that the type parameter of the 'NatRepr' must+-- be the same as the second type parameter of @T@.
src/Data/Parameterized/TraversableF.hs view
@@ -24,11 +24,10 @@ import Control.Applicative import Control.Monad.Identity import Data.Coerce-import Data.Functor.Const import Data.Monoid import GHC.Exts (build) --- | A parameterized type that is a function on all instances.+-- | A parameterized type that is a functor on all instances. class FunctorF m where fmapF :: (forall x . f x -> g x) -> m f -> m g @@ -38,7 +37,7 @@ ------------------------------------------------------------------------ -- FoldableF --- | This is a coercision used to avoid overhead associated+-- | This is a coercion used to avoid overhead associated -- with function composition. (#.) :: Coercible b c => (b -> c) -> (a -> b) -> (a -> c) (#.) _f = coerce
src/Data/Parameterized/TraversableFC.hs view
@@ -38,9 +38,9 @@ import Data.Parameterized.Classes -- | A parameterized type that is a function on all instances.-class FunctorFC m where- fmapFC :: forall f g. (forall x . f x -> g x) ->- (forall x . m f x -> m g x)+class FunctorFC (t :: (k -> *) -> l -> *) where+ fmapFC :: forall f g. (forall x. f x -> g x) ->+ (forall x. t f x -> t g x) -- | A parameterized class for types which can be shown, when given -- functions to show parameterized subterms.@@ -89,74 +89,73 @@ -- | Map each element of the structure to a monoid, -- and combine the results.- foldMapFC :: Monoid m => (forall s . e s -> m) -> t e c -> m+ foldMapFC :: forall f m. Monoid m => (forall x. f x -> m) -> (forall x. t f x -> m) foldMapFC f = foldrFC (mappend . f) mempty -- | Right-associative fold of a structure.- foldrFC :: (forall s . e s -> b -> b) -> b -> t e c -> b+ foldrFC :: forall f b. (forall x. f x -> b -> b) -> (forall x. b -> t f x -> b) foldrFC f z t = appEndo (foldMapFC (Endo #. f) t) z -- | Left-associative fold of a structure.- foldlFC :: (forall s . b -> e s -> b) -> b -> t e c -> b+ foldlFC :: forall f b. (forall x. b -> f x -> b) -> (forall x. b -> t f x -> b) foldlFC f z t = appEndo (getDual (foldMapFC (\e -> Dual (Endo (\r -> f r e))) t)) z -- | Right-associative fold of a structure, -- but with strict application of the operator.- foldrFC' :: (forall s . e s -> b -> b) -> b -> t e c -> b+ foldrFC' :: forall f b. (forall x. f x -> b -> b) -> (forall x. b -> t f x -> b) foldrFC' f0 z0 xs = foldlFC (f' f0) id xs z0 where f' f k x z = k $! f x z -- | Left-associative fold of a parameterized structure -- with a strict accumulator.- foldlFC' :: (forall s . b -> e s -> b) -> b -> t e c -> b+ foldlFC' :: forall f b. (forall x. b -> f x -> b) -> (forall x. b -> t f x -> b) foldlFC' f0 z0 xs = foldrFC (f' f0) id xs z0 where f' f x k z = k $! f z x -- | Convert structure to list.- toListFC :: (forall tp . f tp -> a) -> t f c -> [a]+ toListFC :: forall f a. (forall x. f x -> a) -> (forall x. t f x -> [a]) toListFC f t = build (\c n -> foldrFC (\e v -> c (f e) v) n t) -- | Return 'True' if all values satisfy predicate.-allFC :: FoldableFC t => (forall tp . f tp -> Bool) -> t f c -> Bool+allFC :: FoldableFC t => (forall x. f x -> Bool) -> (forall x. t f x -> Bool) allFC p = getAll #. foldMapFC (All #. p) -- | Return 'True' if any values satisfy predicate.-anyFC :: FoldableFC t => (forall tp . f tp -> Bool) -> t f c -> Bool+anyFC :: FoldableFC t => (forall x. f x -> Bool) -> (forall x. t f x -> Bool) anyFC p = getAny #. foldMapFC (Any #. p) -- | Return number of elements in list.-lengthFC :: FoldableFC t => t e c -> Int+lengthFC :: FoldableFC t => t f x -> Int lengthFC = foldrFC (const (+1)) 0 ------------------------------------------------------------------------ -- TraversableF -class (FunctorFC t, FoldableFC t) => TraversableFC t where- traverseFC :: Applicative m- => (forall s . e s -> m (f s))- -> t e c- -> m (t f c)+class (FunctorFC t, FoldableFC t) => TraversableFC (t :: (k -> *) -> l -> *) where+ traverseFC :: forall f g m. Applicative m+ => (forall x. f x -> m (g x))+ -> (forall x. t f x -> m (t g x)) -- | This function may be used as a value for `fmapF` in a `FunctorF` -- instance.-fmapFCDefault :: TraversableFC t => (forall s . e s -> f s) -> t e c -> t f c+fmapFCDefault :: TraversableFC t => forall f g. (forall x. f x -> g x) -> (forall x. t f x -> t g x) fmapFCDefault = \f -> runIdentity . traverseFC (Identity . f) {-# INLINE fmapFCDefault #-} -- | This function may be used as a value for `Data.Foldable.foldMap` -- in a `Foldable` instance.-foldMapFCDefault :: (TraversableFC t, Monoid m) => (forall s . e s -> m) -> t e c -> m+foldMapFCDefault :: (TraversableFC t, Monoid m) => (forall x. f x -> m) -> (forall x. t f x -> m) foldMapFCDefault = \f -> getConst . traverseFC (Const . f) {-# INLINE foldMapFCDefault #-} -- | Map each element of a structure to an action, evaluate -- these actions from left to right, and ignore the results.-traverseFC_ :: (FoldableFC t, Applicative f) => (forall s . e s -> f ()) -> t e c -> f ()+traverseFC_ :: (FoldableFC t, Applicative m) => (forall x. f x -> m ()) -> (forall x. t f x -> m ()) traverseFC_ f = foldrFC (\e r -> f e *> r) (pure ()) {-# INLINE traverseFC_ #-} -- | Map each element of a structure to an action, evaluate -- these actions from left to right, and ignore the results.-forMFC_ :: (FoldableFC t, Applicative f) => t e c -> (forall s . e s -> f ()) -> f ()+forMFC_ :: (FoldableFC t, Applicative m) => t f c -> (forall x. f x -> m ()) -> m () forMFC_ v f = traverseFC_ f v {-# INLINE forMFC_ #-}
test/Test/Context.hs view
@@ -11,6 +11,7 @@ import Test.QuickCheck import Test.Tasty.QuickCheck +import Control.Lens import Data.Parameterized.Classes import Data.Parameterized.TraversableFC import Data.Parameterized.Some@@ -90,8 +91,8 @@ Some a <- return $ mkUAsgn vals let vals' = toListFC Some a return (vals == vals')- , testProperty "adjust_test" $ \v vs i -> ioProperty $ do- let vals = v:vs+ , testProperty "adjust test monadic" $ \v vs i -> ioProperty $ do+ let vals = v:vs -- ensures vals is not an empty array Some x <- return $ mkUAsgn vals Some y <- return $ mkSAsgn vals let i' = min (max 0 i) (length vals - 1)@@ -99,10 +100,61 @@ Just (Some idx_x) <- return $ U.intIndex i' (U.size x) Just (Some idx_y) <- return $ S.intIndex i' (S.size y) - let x' = U.adjust twiddle idx_x x- let y' = S.adjust twiddle idx_y y+ x' <- U.adjustM (return . twiddle) idx_x x+ y' <- S.adjustM (return . twiddle) idx_y y return (toListFC Some x' == toListFC Some y')++ , testProperty "adjust test" $ \v vs i -> ioProperty $ do+ let vals = v:vs -- ensures vals is not an empty array+ Some x <- return $ mkUAsgn vals+ Some y <- return $ mkSAsgn vals+ let i' = min (max 0 i) (length vals - 1)++ Just (Some idx_x) <- return $ U.intIndex i' (U.size x)+ Just (Some idx_y) <- return $ S.intIndex i' (S.size y)++ let x' = over (ixF idx_x) twiddle x+ y' = (ixF idx_y) %~ twiddle $ y+ x'' = U.adjust twiddle idx_x x+ y'' = S.adjust twiddle idx_y y++ return (toListFC Some x' == toListFC Some y' &&+ -- adjust actually modified the entry+ toListFC Some x /= toListFC Some x' &&+ toListFC Some y /= toListFC Some y' &&+ -- verify new version is equivalent to older deprecated version+ toListFC Some x'' == toListFC Some x' &&+ toListFC Some y'' == toListFC Some y')++ , testProperty "update test" $ \v vs i -> ioProperty $ do+ let vals = v:vs -- ensures vals is not an empty array+ Some x <- return $ mkUAsgn vals+ Some y <- return $ mkSAsgn vals+ let i' = min (max 0 i) (length vals - 1)++ Just (Some idx_x) <- return $ U.intIndex i' (U.size x)+ Just (Some idx_y) <- return $ S.intIndex i' (S.size y)++ let x' = over (ixF idx_x) twiddle x+ y' = (ixF idx_y) %~ twiddle $ y+ updX = set (ixF idx_x) (x' U.! idx_x) x+ updY = (ixF idx_y) .~ (y' S.! idx_y) $ y+ updX' = U.update idx_x (x' U.! idx_x) x+ updY' = S.update idx_y (y' S.! idx_y) y++ return (toListFC Some updX == toListFC Some updY &&+ -- update actually modified the entry+ toListFC Some x /= toListFC Some updX &&+ toListFC Some y /= toListFC Some updY &&+ -- update modified the expected entry+ toListFC Some x' == toListFC Some updX &&+ toListFC Some y' == toListFC Some updY &&+ -- verify new version is equivalent to older deprecated version+ toListFC Some updX == toListFC Some updX' &&+ toListFC Some updY == toListFC Some updY'+ )+ , testProperty "safe_eq" $ \vals1 vals2 -> ioProperty $ do Some x <- return $ mkSAsgn vals1 Some y <- return $ mkSAsgn vals2