dimensions 1.0.1.1 → 2.0.0.0
raw patch · 24 files changed
+2913/−2568 lines, 24 filesdep +constraints-derivingdep +ghcdep ~basePVP ok
version bump matches the API change (PVP)
Dependencies added: constraints-deriving, ghc
Dependency ranges changed: base
API changes (from Hackage documentation)
- Numeric.Dim: N :: Nat -> XNat
- Numeric.Dim: XN :: Nat -> XNat
- Numeric.Dim: [DimNat] :: DimKind Nat
- Numeric.Dim: [DimXNat] :: DimKind XNat
- Numeric.Dim: [Nt] :: XNatType ( 'N n)
- Numeric.Dim: [XNt] :: XNatType ( 'XN m)
- Numeric.Dim: class KnownDim (n :: k)
- Numeric.Dim: class KnownDimKind k
- Numeric.Dim: class KnownXNatType (n :: XNat)
- Numeric.Dim: compareDim :: Dim a -> Dim b -> Ordering
- Numeric.Dim: compareDim' :: forall a b p q. (KnownDim a, KnownDim b) => p a -> q b -> Ordering
- Numeric.Dim: constrain :: forall (m :: Nat) x. KnownDim m => Dim x -> Maybe (Dim (XN m))
- Numeric.Dim: constrainBy :: forall m x. Dim m -> Dim x -> Maybe (Dim (XN m))
- Numeric.Dim: data Dim (x :: k)
- Numeric.Dim: data DimKind :: Type -> Type
- Numeric.Dim: data Nat
- Numeric.Dim: data XNat
- Numeric.Dim: data XNatType :: XNat -> Type
- Numeric.Dim: dim :: KnownDim n => Dim n
- Numeric.Dim: dimKind :: KnownDimKind k => DimKind k
- Numeric.Dim: dimVal :: Dim (x :: k) -> Word
- Numeric.Dim: dimVal' :: forall n. KnownDim n => Word
- Numeric.Dim: inferDimLE :: forall m n. MinDim m n => Evidence (m <= n)
- Numeric.Dim: instance GHC.Classes.Eq (Numeric.Dim.Dim n)
- Numeric.Dim: instance GHC.Classes.Eq (Numeric.Dim.Dim x)
- Numeric.Dim: instance GHC.Classes.Ord (Numeric.Dim.Dim n)
- Numeric.Dim: instance GHC.Classes.Ord (Numeric.Dim.Dim x)
- Numeric.Dim: instance GHC.TypeNats.KnownNat n => Numeric.Dim.KnownDim n
- Numeric.Dim: instance Numeric.Dim.KnownDim 0
- Numeric.Dim: instance Numeric.Dim.KnownDim 1
- Numeric.Dim: instance Numeric.Dim.KnownDim 10
- Numeric.Dim: instance Numeric.Dim.KnownDim 11
- Numeric.Dim: instance Numeric.Dim.KnownDim 12
- Numeric.Dim: instance Numeric.Dim.KnownDim 13
- Numeric.Dim: instance Numeric.Dim.KnownDim 14
- Numeric.Dim: instance Numeric.Dim.KnownDim 15
- Numeric.Dim: instance Numeric.Dim.KnownDim 16
- Numeric.Dim: instance Numeric.Dim.KnownDim 17
- Numeric.Dim: instance Numeric.Dim.KnownDim 18
- Numeric.Dim: instance Numeric.Dim.KnownDim 19
- Numeric.Dim: instance Numeric.Dim.KnownDim 2
- Numeric.Dim: instance Numeric.Dim.KnownDim 20
- Numeric.Dim: instance Numeric.Dim.KnownDim 3
- Numeric.Dim: instance Numeric.Dim.KnownDim 4
- Numeric.Dim: instance Numeric.Dim.KnownDim 5
- Numeric.Dim: instance Numeric.Dim.KnownDim 6
- Numeric.Dim: instance Numeric.Dim.KnownDim 7
- Numeric.Dim: instance Numeric.Dim.KnownDim 8
- Numeric.Dim: instance Numeric.Dim.KnownDim 9
- Numeric.Dim: instance Numeric.Dim.KnownDim m => GHC.Read.Read (Numeric.Dim.Dim ('Numeric.Dim.XN m))
- Numeric.Dim: instance Numeric.Dim.KnownDim n => Numeric.Dim.KnownDim ('Numeric.Dim.N n)
- Numeric.Dim: instance Numeric.Dim.KnownDimKind GHC.Types.Nat
- Numeric.Dim: instance Numeric.Dim.KnownDimKind Numeric.Dim.XNat
- Numeric.Dim: instance Numeric.Dim.KnownXNatType ('Numeric.Dim.N n)
- Numeric.Dim: instance Numeric.Dim.KnownXNatType ('Numeric.Dim.XN n)
- Numeric.Dim: instance forall k (x :: k). GHC.Show.Show (Numeric.Dim.Dim x)
- Numeric.Dim: minusDim :: MinDim m n => Dim n -> Dim m -> Dim (n - m)
- Numeric.Dim: minusDimM :: Dim n -> Dim m -> Maybe (Dim (n - m))
- Numeric.Dim: plusDim :: Dim n -> Dim m -> Dim (n + m)
- Numeric.Dim: powerDim :: Dim n -> Dim m -> Dim ((^) n m)
- Numeric.Dim: relax :: forall (m :: Nat) (n :: Nat). (MinDim m n) => Dim (XN n) -> Dim (XN m)
- Numeric.Dim: sameDim :: forall (x :: Nat) (y :: Nat). Dim x -> Dim y -> Maybe (Evidence (x ~ y))
- Numeric.Dim: sameDim' :: forall (x :: Nat) (y :: Nat) p q. (KnownDim x, KnownDim y) => p x -> q y -> Maybe (Evidence (x ~ y))
- Numeric.Dim: someDimVal :: Word -> SomeDim
- Numeric.Dim: timesDim :: Dim n -> Dim m -> Dim ((*) n m)
- Numeric.Dim: type N (n :: Nat) = 'N n
- Numeric.Dim: type SomeDim = Dim ( 'XN 0)
- Numeric.Dim: type XN (n :: Nat) = 'XN n
- Numeric.Dim: xNatType :: KnownXNatType n => XNatType n
- Numeric.Dimensions.Dims: SomeDims :: (Dims ns) -> SomeDims
- Numeric.Dimensions.Dims: asSpaceOf :: a ds -> (b ds -> c) -> (b ds -> c)
- Numeric.Dimensions.Dims: class Dimensions (ds :: [k])
- Numeric.Dimensions.Dims: class RepresentableList (xs :: [k])
- Numeric.Dimensions.Dims: class KnownXNatTypes xds => XDimensions (xds :: [XNat])
- Numeric.Dimensions.Dims: compareDims :: Dims as -> Dims bs -> Ordering
- Numeric.Dimensions.Dims: compareDims' :: forall as bs p q. (Dimensions as, Dimensions bs) => p as -> q bs -> Ordering
- Numeric.Dimensions.Dims: constrainDims :: XDimensions xds => Dims (ds :: [k]) -> Maybe (Dims xds)
- Numeric.Dimensions.Dims: data SomeDims
- Numeric.Dimensions.Dims: data TypedList (f :: (k -> Type)) (xs :: [k])
- Numeric.Dimensions.Dims: dims :: Dimensions ds => Dims ds
- Numeric.Dimensions.Dims: inSpaceOf :: a ds -> b ds -> a ds
- Numeric.Dimensions.Dims: instance (Numeric.Dimensions.Dims.XDimensions xs, Numeric.Dim.KnownDim m) => Numeric.Dimensions.Dims.XDimensions (Numeric.Dim.XN m : xs)
- Numeric.Dimensions.Dims: instance (Numeric.Dimensions.Dims.XDimensions xs, Numeric.Dim.KnownDim n) => Numeric.Dimensions.Dims.XDimensions (Numeric.Dim.N n : xs)
- Numeric.Dimensions.Dims: instance GHC.Classes.Eq (Numeric.Dimensions.Dims.Dims ds)
- Numeric.Dimensions.Dims: instance GHC.Classes.Eq Numeric.Dimensions.Dims.SomeDims
- Numeric.Dimensions.Dims: instance GHC.Classes.Ord (Numeric.Dimensions.Dims.Dims ds)
- Numeric.Dimensions.Dims: instance GHC.Classes.Ord Numeric.Dimensions.Dims.SomeDims
- Numeric.Dimensions.Dims: instance GHC.Read.Read Numeric.Dimensions.Dims.SomeDims
- Numeric.Dimensions.Dims: instance GHC.Show.Show Numeric.Dimensions.Dims.SomeDims
- Numeric.Dimensions.Dims: instance Numeric.Dimensions.Dims.Dimensions '[]
- Numeric.Dimensions.Dims: instance Numeric.Dimensions.Dims.XDimensions '[]
- Numeric.Dimensions.Dims: instance forall k (d :: k) (ds :: [k]). (Numeric.Dim.KnownDim d, Numeric.Dimensions.Dims.Dimensions ds) => Numeric.Dimensions.Dims.Dimensions (d : ds)
- Numeric.Dimensions.Dims: instance forall k (ds :: [k]). Numeric.Dimensions.Dims.Dimensions ds => GHC.Enum.Bounded (Numeric.Dimensions.Dims.Dims ds)
- Numeric.Dimensions.Dims: instance forall k (xs :: [k]). GHC.Show.Show (Numeric.Dimensions.Dims.Dims xs)
- Numeric.Dimensions.Dims: listDims :: Dims xs -> [Word]
- Numeric.Dimensions.Dims: order :: TypedList f xs -> Dim (Length xs)
- Numeric.Dimensions.Dims: order' :: forall xs. RepresentableList xs => Dim (Length xs)
- Numeric.Dimensions.Dims: sameDims :: Dims (as :: [Nat]) -> Dims (bs :: [Nat]) -> Maybe (Evidence (as ~ bs))
- Numeric.Dimensions.Dims: sameDims' :: forall (as :: [Nat]) (bs :: [Nat]) p q. (Dimensions as, Dimensions bs) => p as -> q bs -> Maybe (Evidence (as ~ bs))
- Numeric.Dimensions.Dims: someDimsVal :: [Word] -> SomeDims
- Numeric.Dimensions.Dims: tList :: RepresentableList xs => TypeList xs
- Numeric.Dimensions.Dims: totalDim :: Dims xs -> Word
- Numeric.Dimensions.Dims: totalDim' :: forall xs. Dimensions xs => Word
- Numeric.Dimensions.Dims: type Dims (xs :: [k]) = TypedList Dim xs
- Numeric.Dimensions.Dims: type KnownXNatTypes xns = All KnownXNatType xns
- Numeric.Dimensions.Dims: type TypeList (xs :: [k]) = TypedList Proxy xs
- Numeric.Dimensions.Dims: types :: TypedList f xs -> TypeList xs
- Numeric.Dimensions.Dims: xDims :: FixedDims xns ns => Dims ns -> Dims xns
- Numeric.Dimensions.Dims: xDims' :: forall xns ns. (FixedDims xns ns, Dimensions ns) => Dims xns
- Numeric.Dimensions.Fold: foldDim :: Dims ds -> (Idxs ds -> Int -> a -> a) -> Int -> Int -> a -> a
- Numeric.Dimensions.Fold: foldDimIdx :: Dims ds -> (Idxs ds -> a -> a) -> a -> a
- Numeric.Dimensions.Fold: foldDimOff :: Dims ds -> (Int -> a -> a) -> Int -> Int -> a -> a
- Numeric.Dimensions.Fold: foldDimReverse :: Dims ds -> (Idxs ds -> Int -> a -> a) -> Int -> Int -> a -> a
- Numeric.Dimensions.Fold: foldDimReverseIdx :: Dims ds -> (Idxs ds -> a -> a) -> a -> a
- Numeric.Dimensions.Fold: overDim :: Monad m => Dims ds -> (Idxs ds -> Int -> a -> m a) -> Int -> Int -> a -> m a
- Numeric.Dimensions.Fold: overDimIdx :: Monad m => Dims ds -> (Idxs ds -> a -> m a) -> a -> m a
- Numeric.Dimensions.Fold: overDimIdx_ :: Monad m => Dims ds -> (Idxs ds -> m ()) -> m ()
- Numeric.Dimensions.Fold: overDimOff :: Monad m => Dims ds -> (Int -> a -> m a) -> Int -> Int -> a -> m a
- Numeric.Dimensions.Fold: overDimOff_ :: Monad m => Dims ds -> (Int -> m ()) -> Int -> Int -> m ()
- Numeric.Dimensions.Fold: overDimPart :: (Dimensions ds, Monad m) => Idxs ds -> Idxs ds -> (Idxs ds -> Int -> a -> m a) -> Int -> Int -> a -> m a
- Numeric.Dimensions.Fold: overDimPartIdx :: Monad m => Idxs ds -> Idxs ds -> (Idxs ds -> a -> m a) -> a -> m a
- Numeric.Dimensions.Fold: overDimReverse :: Monad m => Dims ds -> (Idxs ds -> Int -> a -> m a) -> Int -> Int -> a -> m a
- Numeric.Dimensions.Fold: overDimReverseIdx :: Monad m => Dims ds -> (Idxs ds -> a -> m a) -> a -> m a
- Numeric.Dimensions.Fold: overDim_ :: Monad m => Dims ds -> (Idxs ds -> Int -> m ()) -> Int -> Int -> m ()
- Numeric.Dimensions.Idxs: Idx :: Word -> Idx n
- Numeric.Dimensions.Idxs: [unIdx] :: Idx n -> Word
- Numeric.Dimensions.Idxs: idxFromWord :: forall d. KnownDim d => Word -> Maybe (Idx d)
- Numeric.Dimensions.Idxs: idxToWord :: Idx d -> Word
- Numeric.Dimensions.Idxs: idxsFromWords :: forall ds. Dimensions ds => [Word] -> Maybe (Idx ds)
- Numeric.Dimensions.Idxs: instance GHC.Generics.Generic1 Numeric.Dimensions.Idxs.Idx
- Numeric.Dimensions.Idxs: instance forall k (ds :: [k]). Numeric.Dimensions.Dims.Dimensions ds => GHC.Enum.Bounded (Numeric.Dimensions.Idxs.Idxs ds)
- Numeric.Dimensions.Idxs: instance forall k (ds :: [k]). Numeric.Dimensions.Dims.Dimensions ds => GHC.Enum.Enum (Numeric.Dimensions.Idxs.Idxs ds)
- Numeric.Dimensions.Idxs: instance forall k (n :: k). (Data.Typeable.Internal.Typeable n, Data.Typeable.Internal.Typeable k) => Data.Data.Data (Numeric.Dimensions.Idxs.Idx n)
- Numeric.Dimensions.Idxs: instance forall k (n :: k). Foreign.Storable.Storable (Numeric.Dimensions.Idxs.Idx n)
- Numeric.Dimensions.Idxs: instance forall k (n :: k). GHC.Classes.Eq (Numeric.Dimensions.Idxs.Idx n)
- Numeric.Dimensions.Idxs: instance forall k (n :: k). GHC.Classes.Ord (Numeric.Dimensions.Idxs.Idx n)
- Numeric.Dimensions.Idxs: instance forall k (n :: k). GHC.Generics.Generic (Numeric.Dimensions.Idxs.Idx n)
- Numeric.Dimensions.Idxs: instance forall k (n :: k). GHC.Read.Read (Numeric.Dimensions.Idxs.Idx n)
- Numeric.Dimensions.Idxs: instance forall k (n :: k). GHC.Show.Show (Numeric.Dimensions.Idxs.Idx n)
- Numeric.Dimensions.Idxs: instance forall k (n :: k). Numeric.Dim.KnownDim n => GHC.Enum.Bounded (Numeric.Dimensions.Idxs.Idx n)
- Numeric.Dimensions.Idxs: instance forall k (n :: k). Numeric.Dim.KnownDim n => GHC.Enum.Enum (Numeric.Dimensions.Idxs.Idx n)
- Numeric.Dimensions.Idxs: instance forall k (n :: k). Numeric.Dim.KnownDim n => GHC.Num.Num (Numeric.Dimensions.Idxs.Idx n)
- Numeric.Dimensions.Idxs: instance forall k (n :: k). Numeric.Dim.KnownDim n => GHC.Num.Num (Numeric.Dimensions.Idxs.Idxs '[n])
- Numeric.Dimensions.Idxs: instance forall k (n :: k). Numeric.Dim.KnownDim n => GHC.Real.Integral (Numeric.Dimensions.Idxs.Idx n)
- Numeric.Dimensions.Idxs: instance forall k (n :: k). Numeric.Dim.KnownDim n => GHC.Real.Real (Numeric.Dimensions.Idxs.Idx n)
- Numeric.Dimensions.Idxs: instance forall k (xs :: [k]). GHC.Classes.Eq (Numeric.Dimensions.Idxs.Idxs xs)
- Numeric.Dimensions.Idxs: instance forall k (xs :: [k]). GHC.Classes.Ord (Numeric.Dimensions.Idxs.Idxs xs)
- Numeric.Dimensions.Idxs: instance forall k (xs :: [k]). GHC.Show.Show (Numeric.Dimensions.Idxs.Idxs xs)
- Numeric.Dimensions.Idxs: listIdxs :: Idxs xs -> [Word]
- Numeric.Dimensions.Idxs: newtype Idx n
- Numeric.Dimensions.Idxs: type Idxs (xs :: [k]) = TypedList Idx xs
- Numeric.Dimensions.Idxs: unsafeIdxFromWord :: forall d. KnownDim d => Word -> Idx d
- Numeric.Tuple.Lazy: instance (GHC.Base.Semigroup (Numeric.Tuple.Lazy.Tuple xs), Numeric.TypedList.RepresentableList xs, Numeric.Type.List.All GHC.Base.Monoid xs) => GHC.Base.Monoid (Numeric.Tuple.Lazy.Tuple xs)
- Numeric.Tuple.Lazy: instance (Numeric.Type.List.All GHC.Classes.Eq xs, Numeric.Type.List.All GHC.Classes.Ord xs) => GHC.Classes.Ord (Numeric.Tuple.Lazy.Tuple xs)
- Numeric.Tuple.Lazy: instance (Numeric.TypedList.RepresentableList xs, Numeric.Type.List.All GHC.Enum.Bounded xs) => GHC.Enum.Bounded (Numeric.Tuple.Lazy.Tuple xs)
- Numeric.Tuple.Lazy: instance (Numeric.TypedList.RepresentableList xs, Numeric.Type.List.All GHC.Read.Read xs) => GHC.Read.Read (Numeric.Tuple.Lazy.Tuple xs)
- Numeric.Tuple.Lazy: instance Numeric.Type.List.All GHC.Base.Semigroup xs => GHC.Base.Semigroup (Numeric.Tuple.Lazy.Tuple xs)
- Numeric.Tuple.Lazy: instance Numeric.Type.List.All GHC.Classes.Eq xs => GHC.Classes.Eq (Numeric.Tuple.Lazy.Tuple xs)
- Numeric.Tuple.Lazy: instance Numeric.Type.List.All GHC.Show.Show xs => GHC.Show.Show (Numeric.Tuple.Lazy.Tuple xs)
- Numeric.Tuple.Strict: instance (GHC.Base.Semigroup (Numeric.Tuple.Strict.Tuple xs), Numeric.TypedList.RepresentableList xs, Numeric.Type.List.All GHC.Base.Monoid xs) => GHC.Base.Monoid (Numeric.Tuple.Strict.Tuple xs)
- Numeric.Tuple.Strict: instance (Numeric.Type.List.All GHC.Classes.Eq xs, Numeric.Type.List.All GHC.Classes.Ord xs) => GHC.Classes.Ord (Numeric.Tuple.Strict.Tuple xs)
- Numeric.Tuple.Strict: instance (Numeric.TypedList.RepresentableList xs, Numeric.Type.List.All GHC.Enum.Bounded xs) => GHC.Enum.Bounded (Numeric.Tuple.Strict.Tuple xs)
- Numeric.Tuple.Strict: instance (Numeric.TypedList.RepresentableList xs, Numeric.Type.List.All GHC.Read.Read xs) => GHC.Read.Read (Numeric.Tuple.Strict.Tuple xs)
- Numeric.Tuple.Strict: instance Numeric.Type.List.All GHC.Base.Semigroup xs => GHC.Base.Semigroup (Numeric.Tuple.Strict.Tuple xs)
- Numeric.Tuple.Strict: instance Numeric.Type.List.All GHC.Classes.Eq xs => GHC.Classes.Eq (Numeric.Tuple.Strict.Tuple xs)
- Numeric.Tuple.Strict: instance Numeric.Type.List.All GHC.Show.Show xs => GHC.Show.Show (Numeric.Tuple.Strict.Tuple xs)
- Numeric.Type.Evidence: (+!+) :: Evidence a -> Evidence b -> Evidence (a, b)
- Numeric.Type.Evidence: [E'] :: c a => Evidence' c a
- Numeric.Type.Evidence: [E] :: a => Evidence a
- Numeric.Type.Evidence: data Evidence :: Constraint -> Type
- Numeric.Type.Evidence: data Evidence' :: (k -> Constraint) -> k -> Type
- Numeric.Type.Evidence: infixl 4 +!+
- Numeric.Type.Evidence: sumEvs :: Evidence a -> Evidence b -> Evidence (a, b)
- Numeric.Type.Evidence: toEvidence :: Evidence' c a -> Evidence (c a)
- Numeric.Type.Evidence: toEvidence' :: Evidence (c a) -> Evidence' c a
- Numeric.Type.Evidence: withEvidence :: Evidence a -> (a => r) -> r
- Numeric.Type.List: class (asbs ~ Concat as bs, as ~ Prefix bs asbs, bs ~ Suffix as asbs, IsSuffix bs asbs ~ 'True, IsPrefix as asbs ~ 'True) => ConcatList (as :: [k]) (bs :: [k]) (asbs :: [k]) | as bs -> asbs, as asbs -> bs, bs asbs -> as
- Numeric.Type.List: instance forall k (asbs :: [k]) (as :: [k]) (bs :: [k]). (asbs ~ Numeric.Type.List.Concat as bs, as ~ Numeric.Type.List.Prefix bs asbs, bs ~ Numeric.Type.List.Suffix as asbs, Numeric.Type.List.IsSuffix bs asbs ~ 'GHC.Types.True, Numeric.Type.List.IsPrefix as asbs ~ 'GHC.Types.True) => Numeric.Type.List.ConcatList as bs asbs
- Numeric.Type.List: type (a :: k) :+ (as :: [k]) = a : as
- Numeric.Type.List: type Concat (as :: [k]) (bs :: [k]) = as ++ bs
- Numeric.Type.List: type Cons (n :: k) (ns :: [k]) = n :+ ns
- Numeric.Type.List: type Empty = '[]
- Numeric.Type.List: type Reverse (xs :: [k]) = Reversed k (DoReverse k xs)
- Numeric.Type.List: type Snoc (ns :: [k]) (n :: k) = GetSnoc k (DoSnoc k ns n)
+ Data.Type.List: evConcat :: forall (k :: Type) (as :: [k]) (bs :: [k]) (asbs :: [k]). (asbs ~ Concat as bs) :- ConcatList as bs asbs
+ Data.Type.List: evStripPrefix :: forall (k :: Type) (as :: [k]) (bs :: [k]) (asbs :: [k]). (bs ~ StripPrefix as asbs) :- ConcatList as bs asbs
+ Data.Type.List: evStripSuffix :: forall (k :: Type) (as :: [k]) (bs :: [k]) (asbs :: [k]). (as ~ StripSuffix bs asbs) :- ConcatList as bs asbs
+ Data.Type.List: inferTypeableCons :: forall (k :: Type) (ys :: [k]) (x :: k) (xs :: [k]). (Typeable ys, ys ~ (x : xs)) => Dict (Typeable x, Typeable xs)
+ Data.Type.List: infixl 6 +:
+ Data.Type.List: infixr 5 :+
+ Data.Type.List: type (a :: k) :+ (as :: [k]) = a : as
+ Data.Type.List: type ConcatList (as :: [k]) (bs :: [k]) (asbs :: [k]) = (asbs ~ Concat as bs, as ~ StripSuffix bs asbs, bs ~ StripPrefix as asbs)
+ Data.Type.List: type Cons (a :: k) (as :: [k]) = a : as
+ Data.Type.List: type Empty = '[]
+ Data.Type.List: type family Elem (x :: k) (xs :: [k]) :: Constraint
+ Data.Type.Lits: [:$$:] :: () => ErrorMessage -> ErrorMessage -> ErrorMessage
+ Data.Type.Lits: [:<>:] :: () => ErrorMessage -> ErrorMessage -> ErrorMessage
+ Data.Type.Lits: [SEQ] :: SOrdering 'EQ
+ Data.Type.Lits: [SGT] :: SOrdering 'GT
+ Data.Type.Lits: [SLT] :: SOrdering 'LT
+ Data.Type.Lits: [ShowType] :: forall t. () => t -> ErrorMessage
+ Data.Type.Lits: [SomeNat] :: forall (n :: Nat). KnownNat n => Proxy n -> SomeNat
+ Data.Type.Lits: [SomeSymbol] :: forall (n :: Symbol). KnownSymbol n => Proxy n -> SomeSymbol
+ Data.Type.Lits: [Text] :: () => Symbol -> ErrorMessage
+ Data.Type.Lits: class KnownNat (n :: Nat)
+ Data.Type.Lits: class KnownSymbol (n :: Symbol)
+ Data.Type.Lits: cmpNat :: forall (a :: Nat) (b :: Nat) (proxy :: Nat -> Type). (KnownNat a, KnownNat b) => proxy a -> proxy b -> SOrdering (CmpNat a b)
+ Data.Type.Lits: cmpSymbol :: forall (a :: Symbol) (b :: Symbol) (proxy :: Symbol -> Type). (KnownSymbol a, KnownSymbol b) => proxy a -> proxy b -> SOrdering (CmpSymbol a b)
+ Data.Type.Lits: data ErrorMessage
+ Data.Type.Lits: data Nat
+ Data.Type.Lits: data SOrdering :: Ordering -> Type
+ Data.Type.Lits: data SomeNat
+ Data.Type.Lits: data SomeSymbol
+ Data.Type.Lits: data Symbol
+ Data.Type.Lits: infixl 5 :$$:
+ Data.Type.Lits: infixl 6 :<>:
+ Data.Type.Lits: infixl 7 `Mod`
+ Data.Type.Lits: infixr 8 ^
+ Data.Type.Lits: natVal :: KnownNat n => proxy n -> Natural
+ Data.Type.Lits: natVal' :: KnownNat n => Proxy# n -> Natural
+ Data.Type.Lits: sameNat :: (KnownNat a, KnownNat b) => Proxy a -> Proxy b -> Maybe (a :~: b)
+ Data.Type.Lits: sameSymbol :: (KnownSymbol a, KnownSymbol b) => Proxy a -> Proxy b -> Maybe (a :~: b)
+ Data.Type.Lits: someNatVal :: Natural -> SomeNat
+ Data.Type.Lits: someSymbolVal :: String -> SomeSymbol
+ Data.Type.Lits: symbolVal :: KnownSymbol n => proxy n -> String
+ Data.Type.Lits: symbolVal' :: KnownSymbol n => Proxy# n -> String
+ Data.Type.Lits: type (<=) (a :: Nat) (b :: Nat) = LE a b (CmpNat a b)
+ Data.Type.Lits: type family TypeError (a :: ErrorMessage) :: b
+ Numeric.Dimensions: (\\) :: HasDict c e => (c -> r) -> e -> r
+ Numeric.Dimensions: Sub :: (a -> Dict b) -> (:-) a b
+ Numeric.Dimensions: [Dict] :: forall a. a => Dict a
+ Numeric.Dimensions: data Dict a
+ Numeric.Dimensions: infixl 1 \\
+ Numeric.Dimensions: infixr 9 :-
+ Numeric.Dimensions: mapDict :: () => (a :- b) -> Dict a -> Dict b
+ Numeric.Dimensions: newtype (:-) a b
+ Numeric.Dimensions.Dim: -- <a>DimBound</a>.
+ Numeric.Dimensions.Dim: -- both <tt>Nat</tt> and <tt>Xnat</tt> indexed dims).
+ Numeric.Dimensions.Dim: -- safe to index something by an index less than <tt>DimBound n</tt> (for
+ Numeric.Dimensions.Dim: -- | Minimal or exact bound of <tt>Dims</tt>. This is a plural form of
+ Numeric.Dimensions.Dim: N :: Nat -> XNat
+ Numeric.Dimensions.Dim: SomeDims :: Dims ns -> SomeDims
+ Numeric.Dimensions.Dim: XN :: Nat -> XNat
+ Numeric.Dimensions.Dim: [DimNat] :: DimKind Nat
+ Numeric.Dimensions.Dim: [DimXNat] :: DimKind XNat
+ Numeric.Dimensions.Dim: [Nt] :: XNatType ( 'N n)
+ Numeric.Dimensions.Dim: [SEQ] :: SOrdering 'EQ
+ Numeric.Dimensions.Dim: [SGT] :: SOrdering 'GT
+ Numeric.Dimensions.Dim: [SLT] :: SOrdering 'LT
+ Numeric.Dimensions.Dim: [XNt] :: XNatType ( 'XN m)
+ Numeric.Dimensions.Dim: asSpaceOf :: forall (k :: Type) (ds :: [k]) (p :: [k] -> Type) (q :: [k] -> Type) (r :: Type). p ds -> (q ds -> r) -> q ds -> r
+ Numeric.Dimensions.Dim: class KnownDimKind k => BoundedDim (n :: k) where {
+ Numeric.Dimensions.Dim: class KnownDimKind k => BoundedDims (ds :: [k]) where {
+ Numeric.Dimensions.Dim: class Dimensions (ds :: [Nat])
+ Numeric.Dimensions.Dim: class KnownDim (n :: Nat)
+ Numeric.Dimensions.Dim: class KnownDimKind (k :: Type)
+ Numeric.Dimensions.Dim: class KnownXNatType (n :: XNat)
+ Numeric.Dimensions.Dim: class RepresentableList (xs :: [k])
+ Numeric.Dimensions.Dim: compareDim :: forall (a :: Nat) (b :: Nat). Dim a -> Dim b -> SOrdering (CmpNat a b)
+ Numeric.Dimensions.Dim: compareDim' :: forall (a :: Nat) (b :: Nat) (p :: Nat -> Type) (q :: Nat -> Type). (KnownDim a, KnownDim b) => p a -> q b -> SOrdering (CmpNat a b)
+ Numeric.Dimensions.Dim: constrainBy :: forall (k :: Type) (x :: k) (p :: k -> Type) (l :: Type) (y :: l). BoundedDim x => p x -> Dim y -> Maybe (Dim x)
+ Numeric.Dimensions.Dim: constrainDim :: forall (l :: Type) (y :: l). BoundedDim n => Dim y -> Maybe (Dim n)
+ Numeric.Dimensions.Dim: constrainDims :: forall (l :: Type) (ys :: [l]). BoundedDims ds => Dims ys -> Maybe (Dims ds)
+ Numeric.Dimensions.Dim: data Dim (x :: k)
+ Numeric.Dimensions.Dim: data DimKind :: Type -> Type
+ Numeric.Dimensions.Dim: data Nat
+ Numeric.Dimensions.Dim: data SOrdering :: Ordering -> Type
+ Numeric.Dimensions.Dim: data SomeDims
+ Numeric.Dimensions.Dim: data TypedList (f :: (k -> Type)) (xs :: [k])
+ Numeric.Dimensions.Dim: data XNat
+ Numeric.Dimensions.Dim: data XNatType :: XNat -> Type
+ Numeric.Dimensions.Dim: dim :: KnownDim n => Dim n
+ Numeric.Dimensions.Dim: dimBound :: BoundedDim n => Dim (DimBound n)
+ Numeric.Dimensions.Dim: dimKind :: KnownDimKind k => DimKind k
+ Numeric.Dimensions.Dim: dimVal :: forall (k :: Type) (x :: k). Dim (x :: k) -> Word
+ Numeric.Dimensions.Dim: dimVal' :: forall (n :: Nat). KnownDim n => Word
+ Numeric.Dimensions.Dim: dims :: Dimensions ds => Dims ds
+ Numeric.Dimensions.Dim: dimsBound :: BoundedDims ds => Dims (DimsBound ds)
+ Numeric.Dimensions.Dim: divDim :: forall (n :: Nat) (m :: Nat). Dim n -> Dim m -> Dim (Div n m)
+ Numeric.Dimensions.Dim: inSpaceOf :: forall (k :: Type) (ds :: [k]) (p :: [k] -> Type) (q :: [k] -> Type). p ds -> q ds -> p ds
+ Numeric.Dimensions.Dim: inferAllBoundedDims :: BoundedDims ds => Dict (All BoundedDim ds, RepresentableList ds)
+ Numeric.Dimensions.Dim: inferTypeableDims :: forall (ds :: [Nat]). Dims ds -> Dict (Typeable ds)
+ Numeric.Dimensions.Dim: infixl 6 -
+ Numeric.Dimensions.Dim: infixl 7 *
+ Numeric.Dimensions.Dim: infixr 5 :*
+ Numeric.Dimensions.Dim: infixr 8 ^
+ Numeric.Dimensions.Dim: instance (Numeric.Dimensions.Dim.BoundedDim n, Numeric.Dimensions.Dim.BoundedDims ns) => Numeric.Dimensions.Dim.BoundedDims (n : ns)
+ Numeric.Dimensions.Dim: instance (Numeric.Dimensions.Dim.KnownDim d, Numeric.Dimensions.Dim.Dimensions ds) => Numeric.Dimensions.Dim.Dimensions (d : ds)
+ Numeric.Dimensions.Dim: instance Data.Constraint.Class (GHC.TypeNats.KnownNat n) (Numeric.Dimensions.Dim.KnownDim n)
+ Numeric.Dimensions.Dim: instance Data.Typeable.Internal.Typeable d => Data.Data.Data (Numeric.Dimensions.Dim.Dim d)
+ Numeric.Dimensions.Dim: instance GHC.Classes.Eq (Numeric.Dimensions.Dim.Dim n)
+ Numeric.Dimensions.Dim: instance GHC.Classes.Eq (Numeric.Dimensions.Dim.Dim x)
+ Numeric.Dimensions.Dim: instance GHC.Classes.Eq (Numeric.Dimensions.Dim.Dims ds)
+ Numeric.Dimensions.Dim: instance GHC.Classes.Eq Numeric.Dimensions.Dim.SomeDims
+ Numeric.Dimensions.Dim: instance GHC.Classes.Ord (Numeric.Dimensions.Dim.Dim n)
+ Numeric.Dimensions.Dim: instance GHC.Classes.Ord (Numeric.Dimensions.Dim.Dim x)
+ Numeric.Dimensions.Dim: instance GHC.Classes.Ord (Numeric.Dimensions.Dim.Dims ds)
+ Numeric.Dimensions.Dim: instance GHC.Classes.Ord Numeric.Dimensions.Dim.SomeDims
+ Numeric.Dimensions.Dim: instance GHC.Read.Read Numeric.Dimensions.Dim.SomeDims
+ Numeric.Dimensions.Dim: instance GHC.Show.Show Numeric.Dimensions.Dim.SomeDims
+ Numeric.Dimensions.Dim: instance GHC.TypeNats.KnownNat n => Numeric.Dimensions.Dim.KnownDim n
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.BoundedDims '[]
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.Dimensions '[]
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.Dimensions ns => Numeric.Dimensions.Dim.BoundedDims ns
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 0
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 1
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 10
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 11
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 12
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 13
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 14
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 15
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 16
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 17
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 18
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 19
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 2
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 20
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 21
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 22
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 23
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 24
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 25
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 3
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 4
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 5
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 6
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 7
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 8
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim 9
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim d => GHC.Generics.Generic (Numeric.Dimensions.Dim.Dim d)
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim m => Numeric.Dimensions.Dim.BoundedDim ('Numeric.Dimensions.Dim.XN m)
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim n => Numeric.Dimensions.Dim.BoundedDim ('Numeric.Dimensions.Dim.N n)
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDim n => Numeric.Dimensions.Dim.BoundedDim n
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDimKind GHC.Types.Nat
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownDimKind Numeric.Dimensions.Dim.XNat
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownXNatType ('Numeric.Dimensions.Dim.N n)
+ Numeric.Dimensions.Dim: instance Numeric.Dimensions.Dim.KnownXNatType ('Numeric.Dimensions.Dim.XN n)
+ Numeric.Dimensions.Dim: instance forall k (x :: k). GHC.Show.Show (Numeric.Dimensions.Dim.Dim x)
+ Numeric.Dimensions.Dim: instance forall k (x :: k). Numeric.Dimensions.Dim.BoundedDim x => GHC.Read.Read (Numeric.Dimensions.Dim.Dim x)
+ Numeric.Dimensions.Dim: instance forall k (xs :: [k]). GHC.Show.Show (Numeric.Dimensions.Dim.Dims xs)
+ Numeric.Dimensions.Dim: instance forall k (xs :: [k]). Numeric.Dimensions.Dim.BoundedDims xs => GHC.Read.Read (Numeric.Dimensions.Dim.Dims xs)
+ Numeric.Dimensions.Dim: listDims :: forall (k :: Type) (xs :: [k]). Dims xs -> [Word]
+ Numeric.Dimensions.Dim: log2Dim :: forall (n :: Nat). Dim n -> Dim (Log2 n)
+ Numeric.Dimensions.Dim: minDim :: forall (k :: Type) (d :: k). BoundedDim d => Dim d
+ Numeric.Dimensions.Dim: minDims :: forall (k :: Type) (ds :: [k]). BoundedDims ds => Dims ds
+ Numeric.Dimensions.Dim: minusDim :: forall (n :: Nat) (m :: Nat). (<=) m n => Dim n -> Dim m -> Dim (n - m)
+ Numeric.Dimensions.Dim: minusDimM :: forall (n :: Nat) (m :: Nat). Dim n -> Dim m -> Maybe (Dim (n - m))
+ Numeric.Dimensions.Dim: modDim :: forall (n :: Nat) (m :: Nat). Dim n -> Dim m -> Dim (Mod n m)
+ Numeric.Dimensions.Dim: order :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). TypedList f xs -> Dim (Length xs)
+ Numeric.Dimensions.Dim: order' :: forall (k :: Type) (xs :: [k]). RepresentableList xs => Dim (Length xs)
+ Numeric.Dimensions.Dim: pattern D25 :: forall (n :: Nat). () => n ~ 25 => Dim n
+ Numeric.Dimensions.Dim: pattern KnownDims :: forall (ds :: [Nat]). () => (All KnownDim ds, All BoundedDim ds, RepresentableList ds, Dimensions ds) => Dims ds
+ Numeric.Dimensions.Dim: pattern TypeList :: forall (k :: Type) (xs :: [k]). () => RepresentableList xs => TypeList xs
+ Numeric.Dimensions.Dim: pattern Reverse :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). () => forall (sx :: [k]). (xs ~ Reverse sx, sx ~ Reverse xs) => TypedList f sx -> TypedList f xs
+ Numeric.Dimensions.Dim: pattern Cons :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). () => forall (y :: k) (ys :: [k]). xs ~ (y : ys) => f y -> TypedList f ys -> TypedList f xs
+ Numeric.Dimensions.Dim: plusDim :: forall (n :: Nat) (m :: Nat). Dim n -> Dim m -> Dim (n + m)
+ Numeric.Dimensions.Dim: powerDim :: forall (n :: Nat) (m :: Nat). Dim n -> Dim m -> Dim ((^) n m)
+ Numeric.Dimensions.Dim: relax :: forall (m :: Nat) (n :: Nat). (<=) m n => Dim (XN n) -> Dim (XN m)
+ Numeric.Dimensions.Dim: sameDim :: forall (x :: Nat) (y :: Nat). Dim x -> Dim y -> Maybe (Dict (x ~ y))
+ Numeric.Dimensions.Dim: sameDim' :: forall (x :: Nat) (y :: Nat) (p :: Nat -> Type) (q :: Nat -> Type). (KnownDim x, KnownDim y) => p x -> q y -> Maybe (Dict (x ~ y))
+ Numeric.Dimensions.Dim: sameDims :: forall (as :: [Nat]) (bs :: [Nat]). Dims as -> Dims bs -> Maybe (Dict (as ~ bs))
+ Numeric.Dimensions.Dim: sameDims' :: forall (as :: [Nat]) (bs :: [Nat]) (p :: [Nat] -> Type) (q :: [Nat] -> Type). (Dimensions as, Dimensions bs) => p as -> q bs -> Maybe (Dict (as ~ bs))
+ Numeric.Dimensions.Dim: someDimVal :: Word -> SomeDim
+ Numeric.Dimensions.Dim: someDimsVal :: [Word] -> SomeDims
+ Numeric.Dimensions.Dim: stripPrefixDims :: forall (xs :: [Nat]) (ys :: [Nat]). Dims xs -> Dims ys -> Maybe (Dims (StripPrefix xs ys))
+ Numeric.Dimensions.Dim: stripSuffixDims :: forall (xs :: [Nat]) (ys :: [Nat]). Dims xs -> Dims ys -> Maybe (Dims (StripSuffix xs ys))
+ Numeric.Dimensions.Dim: tList :: RepresentableList xs => TypeList xs
+ Numeric.Dimensions.Dim: timesDim :: forall (n :: Nat) (m :: Nat). Dim n -> Dim m -> Dim ((*) n m)
+ Numeric.Dimensions.Dim: totalDim :: forall (k :: Type) (xs :: [k]). Dims xs -> Word
+ Numeric.Dimensions.Dim: totalDim' :: forall (xs :: [Nat]). Dimensions xs => Word
+ Numeric.Dimensions.Dim: type (<=) (a :: Nat) (b :: Nat) = LE a b (CmpNat a b)
+ Numeric.Dimensions.Dim: type Dims (xs :: [k]) = TypedList Dim xs
+ Numeric.Dimensions.Dim: type KnownXNatTypes xns = All KnownXNatType xns
+ Numeric.Dimensions.Dim: type N (n :: Nat) = 'N n
+ Numeric.Dimensions.Dim: type SomeDim = Dim ( 'XN 0)
+ Numeric.Dimensions.Dim: type TypeList (xs :: [k]) = TypedList Proxy xs
+ Numeric.Dimensions.Dim: type XN (n :: Nat) = 'XN n
+ Numeric.Dimensions.Dim: type family FixedDims (xns :: [XNat]) (ns :: [Nat]) :: Constraint
+ Numeric.Dimensions.Dim: typeableDim :: forall (n :: Nat). Typeable n => Dim n
+ Numeric.Dimensions.Dim: typeableDims :: forall (ds :: [Nat]). Typeable ds => Dims ds
+ Numeric.Dimensions.Dim: types :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). TypedList f xs -> TypeList xs
+ Numeric.Dimensions.Dim: xDims :: forall (xns :: [XNat]) (ns :: [Nat]). FixedDims xns ns => Dims ns -> Dims xns
+ Numeric.Dimensions.Dim: xDims' :: forall (xns :: [XNat]) (ns :: [Nat]). (FixedDims xns ns, Dimensions ns) => Dims xns
+ Numeric.Dimensions.Dim: xNatType :: KnownXNatType n => XNatType n
+ Numeric.Dimensions.Dim: }
+ Numeric.Dimensions.Idx: data Idx (n :: k)
+ Numeric.Dimensions.Idx: idxFromWord :: forall (k :: Type) (d :: k). BoundedDim d => Word -> Maybe (Idx d)
+ Numeric.Dimensions.Idx: idxToWord :: forall (k :: Type) (d :: k). Idx d -> Word
+ Numeric.Dimensions.Idx: idxsFromWords :: forall (k :: Type) (xs :: [k]). BoundedDims xs => [Word] -> Maybe (Idxs xs)
+ Numeric.Dimensions.Idx: instance Numeric.Dimensions.Dim.Dimensions ds => GHC.Enum.Enum (Numeric.Dimensions.Idx.Idxs ds)
+ Numeric.Dimensions.Idx: instance forall k (ds :: [k]). Numeric.Dimensions.Dim.BoundedDims ds => GHC.Enum.Bounded (Numeric.Dimensions.Idx.Idxs ds)
+ Numeric.Dimensions.Idx: instance forall k (n :: k). (Data.Typeable.Internal.Typeable n, Data.Typeable.Internal.Typeable k) => Data.Data.Data (Numeric.Dimensions.Idx.Idx n)
+ Numeric.Dimensions.Idx: instance forall k (n :: k). Foreign.Storable.Storable (Numeric.Dimensions.Idx.Idx n)
+ Numeric.Dimensions.Idx: instance forall k (n :: k). GHC.Classes.Eq (Numeric.Dimensions.Idx.Idx n)
+ Numeric.Dimensions.Idx: instance forall k (n :: k). GHC.Classes.Ord (Numeric.Dimensions.Idx.Idx n)
+ Numeric.Dimensions.Idx: instance forall k (n :: k). GHC.Generics.Generic (Numeric.Dimensions.Idx.Idx n)
+ Numeric.Dimensions.Idx: instance forall k (n :: k). Numeric.Dimensions.Dim.BoundedDim n => GHC.Enum.Bounded (Numeric.Dimensions.Idx.Idx n)
+ Numeric.Dimensions.Idx: instance forall k (n :: k). Numeric.Dimensions.Dim.BoundedDim n => GHC.Enum.Enum (Numeric.Dimensions.Idx.Idx n)
+ Numeric.Dimensions.Idx: instance forall k (n :: k). Numeric.Dimensions.Dim.BoundedDim n => GHC.Num.Num (Numeric.Dimensions.Idx.Idx n)
+ Numeric.Dimensions.Idx: instance forall k (n :: k). Numeric.Dimensions.Dim.BoundedDim n => GHC.Num.Num (Numeric.Dimensions.Idx.Idxs '[n])
+ Numeric.Dimensions.Idx: instance forall k (n :: k). Numeric.Dimensions.Dim.BoundedDim n => GHC.Real.Integral (Numeric.Dimensions.Idx.Idx n)
+ Numeric.Dimensions.Idx: instance forall k (n :: k). Numeric.Dimensions.Dim.BoundedDim n => GHC.Real.Real (Numeric.Dimensions.Idx.Idx n)
+ Numeric.Dimensions.Idx: instance forall k (x :: k). GHC.Show.Show (Numeric.Dimensions.Idx.Idx x)
+ Numeric.Dimensions.Idx: instance forall k (x :: k). Numeric.Dimensions.Dim.BoundedDim x => GHC.Read.Read (Numeric.Dimensions.Idx.Idx x)
+ Numeric.Dimensions.Idx: instance forall k (xs :: [k]). GHC.Classes.Eq (Numeric.Dimensions.Idx.Idxs xs)
+ Numeric.Dimensions.Idx: instance forall k (xs :: [k]). GHC.Classes.Ord (Numeric.Dimensions.Idx.Idxs xs)
+ Numeric.Dimensions.Idx: instance forall k (xs :: [k]). GHC.Show.Show (Numeric.Dimensions.Idx.Idxs xs)
+ Numeric.Dimensions.Idx: instance forall k (xs :: [k]). Numeric.Dimensions.Dim.BoundedDims xs => GHC.Read.Read (Numeric.Dimensions.Idx.Idxs xs)
+ Numeric.Dimensions.Idx: listIdxs :: forall (k :: Type) (xs :: [k]). Idxs xs -> [Word]
+ Numeric.Dimensions.Idx: pattern Idx :: forall (k :: Type) (n :: k). BoundedDim n => Word -> Idx n
+ Numeric.Dimensions.Idx: type Idxs (xs :: [k]) = TypedList Idx xs
+ Numeric.Dimensions.Idx: unsafeIdxFromWord :: forall (k :: Type) (d :: k). BoundedDim d => Word -> Idx d
+ Numeric.Tuple.Lazy: instance (Data.Type.List.All GHC.Classes.Eq xs, Data.Type.List.All GHC.Classes.Ord xs) => GHC.Classes.Ord (Numeric.Tuple.Lazy.Tuple xs)
+ Numeric.Tuple.Lazy: instance (Data.Type.List.All GHC.Read.Read xs, Numeric.TypedList.RepresentableList xs) => GHC.Read.Read (Numeric.Tuple.Lazy.Tuple xs)
+ Numeric.Tuple.Lazy: instance (Numeric.TypedList.RepresentableList xs, Data.Type.List.All GHC.Base.Semigroup xs, Data.Type.List.All GHC.Base.Monoid xs) => GHC.Base.Monoid (Numeric.Tuple.Lazy.Tuple xs)
+ Numeric.Tuple.Lazy: instance (Numeric.TypedList.RepresentableList xs, Data.Type.List.All GHC.Enum.Bounded xs) => GHC.Enum.Bounded (Numeric.Tuple.Lazy.Tuple xs)
+ Numeric.Tuple.Lazy: instance Data.Functor.Classes.Eq1 Numeric.Tuple.Lazy.Id
+ Numeric.Tuple.Lazy: instance Data.Functor.Classes.Ord1 Numeric.Tuple.Lazy.Id
+ Numeric.Tuple.Lazy: instance Data.Functor.Classes.Read1 Numeric.Tuple.Lazy.Id
+ Numeric.Tuple.Lazy: instance Data.Functor.Classes.Show1 Numeric.Tuple.Lazy.Id
+ Numeric.Tuple.Lazy: instance Data.Type.List.All GHC.Base.Semigroup xs => GHC.Base.Semigroup (Numeric.Tuple.Lazy.Tuple xs)
+ Numeric.Tuple.Lazy: instance Data.Type.List.All GHC.Classes.Eq xs => GHC.Classes.Eq (Numeric.Tuple.Lazy.Tuple xs)
+ Numeric.Tuple.Lazy: instance Data.Type.List.All GHC.Show.Show xs => GHC.Show.Show (Numeric.Tuple.Lazy.Tuple xs)
+ Numeric.Tuple.Lazy: pattern TypeList :: forall (k :: Type) (xs :: [k]). () => RepresentableList xs => TypeList xs
+ Numeric.Tuple.Lazy: pattern Reverse :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). () => forall (sx :: [k]). (xs ~ Reverse sx, sx ~ Reverse xs) => TypedList f sx -> TypedList f xs
+ Numeric.Tuple.Lazy: pattern Cons :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). () => forall (y :: k) (ys :: [k]). xs ~ (y : ys) => f y -> TypedList f ys -> TypedList f xs
+ Numeric.Tuple.Lazy: pattern (:!) :: forall (xs :: [Type]). () => forall (y :: Type) (ys :: [Type]). xs ~ (y : ys) => y -> Tuple ys -> Tuple xs
+ Numeric.Tuple.Strict: instance (Data.Type.List.All GHC.Classes.Eq xs, Data.Type.List.All GHC.Classes.Ord xs) => GHC.Classes.Ord (Numeric.Tuple.Strict.Tuple xs)
+ Numeric.Tuple.Strict: instance (Data.Type.List.All GHC.Read.Read xs, Numeric.TypedList.RepresentableList xs) => GHC.Read.Read (Numeric.Tuple.Strict.Tuple xs)
+ Numeric.Tuple.Strict: instance (Numeric.TypedList.RepresentableList xs, Data.Type.List.All GHC.Base.Semigroup xs, Data.Type.List.All GHC.Base.Monoid xs) => GHC.Base.Monoid (Numeric.Tuple.Strict.Tuple xs)
+ Numeric.Tuple.Strict: instance (Numeric.TypedList.RepresentableList xs, Data.Type.List.All GHC.Enum.Bounded xs) => GHC.Enum.Bounded (Numeric.Tuple.Strict.Tuple xs)
+ Numeric.Tuple.Strict: instance Data.Functor.Classes.Eq1 Numeric.Tuple.Strict.Id
+ Numeric.Tuple.Strict: instance Data.Functor.Classes.Ord1 Numeric.Tuple.Strict.Id
+ Numeric.Tuple.Strict: instance Data.Functor.Classes.Read1 Numeric.Tuple.Strict.Id
+ Numeric.Tuple.Strict: instance Data.Functor.Classes.Show1 Numeric.Tuple.Strict.Id
+ Numeric.Tuple.Strict: instance Data.Type.List.All GHC.Base.Semigroup xs => GHC.Base.Semigroup (Numeric.Tuple.Strict.Tuple xs)
+ Numeric.Tuple.Strict: instance Data.Type.List.All GHC.Classes.Eq xs => GHC.Classes.Eq (Numeric.Tuple.Strict.Tuple xs)
+ Numeric.Tuple.Strict: instance Data.Type.List.All GHC.Show.Show xs => GHC.Show.Show (Numeric.Tuple.Strict.Tuple xs)
+ Numeric.Tuple.Strict: pattern TypeList :: forall (k :: Type) (xs :: [k]). () => RepresentableList xs => TypeList xs
+ Numeric.Tuple.Strict: pattern Reverse :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). () => forall (sx :: [k]). (xs ~ Reverse sx, sx ~ Reverse xs) => TypedList f sx -> TypedList f xs
+ Numeric.Tuple.Strict: pattern Cons :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). () => forall (y :: k) (ys :: [k]). xs ~ (y : ys) => f y -> TypedList f ys -> TypedList f xs
+ Numeric.Tuple.Strict: pattern (:!) :: forall (xs :: [Type]). () => forall (y :: Type) (ys :: [Type]). xs ~ (y : ys) => y -> Tuple ys -> Tuple xs
+ Numeric.TypedList: [Dict1] :: c a => Dict1 c a
+ Numeric.TypedList: data Dict1 :: (k -> Constraint) -> k -> Type
+ Numeric.TypedList: inferTypeableList :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). (Typeable k, All Typeable xs) => TypedList f xs -> Dict (Typeable xs)
+ Numeric.TypedList: infixr 5 :*
+ Numeric.TypedList: instance forall k (f :: k -> *) (xs :: [k]). (Data.Typeable.Internal.Typeable k, Data.Typeable.Internal.Typeable f, Data.Typeable.Internal.Typeable xs, Data.Type.List.All Data.Data.Data (Data.Type.List.Map f xs)) => Data.Data.Data (Numeric.TypedList.TypedList f xs)
+ Numeric.TypedList: instance forall k (f :: k -> *) (xs :: [k]). GHC.Generics.Generic (Numeric.TypedList.TypedList f xs)
+ Numeric.TypedList: instance forall k (p :: k -> GHC.Types.Constraint) (a :: k). (Data.Typeable.Internal.Typeable k, Data.Typeable.Internal.Typeable p, Data.Typeable.Internal.Typeable a, p a) => Data.Data.Data (Numeric.TypedList.Dict1 p a)
+ Numeric.TypedList: instance forall k (p :: k -> GHC.Types.Constraint) (a :: k). GHC.Classes.Eq (Numeric.TypedList.Dict1 p a)
+ Numeric.TypedList: instance forall k (p :: k -> GHC.Types.Constraint) (a :: k). GHC.Classes.Ord (Numeric.TypedList.Dict1 p a)
+ Numeric.TypedList: instance forall k (p :: k -> GHC.Types.Constraint) (a :: k). GHC.Show.Show (Numeric.TypedList.Dict1 p a)
+ Numeric.TypedList: pattern EvList :: forall (k :: Type) (c :: k -> Constraint) (xs :: [k]). () => (All c xs, RepresentableList xs) => DictList c xs
+ Numeric.TypedList: pattern TypeList :: forall (k :: Type) (xs :: [k]). () => RepresentableList xs => TypeList xs
+ Numeric.TypedList: pattern Reverse :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). () => forall (sx :: [k]). (xs ~ Reverse sx, sx ~ Reverse xs) => TypedList f sx -> TypedList f xs
+ Numeric.TypedList: pattern Cons :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). () => forall (y :: k) (ys :: [k]). xs ~ (y : ys) => f y -> TypedList f ys -> TypedList f xs
+ Numeric.TypedList: sameList :: forall (k :: Type) (f :: k -> Type) (xs :: [k]) (ys :: [k]). (All Typeable xs, All Typeable ys, All Eq (Map f xs)) => TypedList f xs -> TypedList f ys -> Maybe (xs :~: ys, Bool)
+ Numeric.TypedList: stripPrefix :: forall (k :: Type) (f :: k -> Type) (xs :: [k]) (ys :: [k]). (All Typeable xs, All Typeable ys, All Eq (Map f xs)) => TypedList f xs -> TypedList f ys -> Maybe (TypedList f (StripPrefix xs ys))
+ Numeric.TypedList: stripSuffix :: forall (k :: Type) (f :: k -> Type) (xs :: [k]) (ys :: [k]). (All Typeable xs, All Typeable ys, All Eq (Map f xs)) => TypedList f xs -> TypedList f ys -> Maybe (TypedList f (StripSuffix xs ys))
+ Numeric.TypedList: type DictList (c :: k -> Constraint) (xs :: [k]) = TypedList (Dict1 c) xs
+ Numeric.TypedList: typeables :: forall (k :: Type) (xs :: [k]). Typeable xs => TypeList xs
+ Numeric.TypedList: typedListReadPrec :: forall (k :: Type) (c :: k -> Constraint) (f :: k -> Type) (xs :: [k]) (g :: k -> Type). All c xs => String -> (forall (x :: k). c x => ReadPrec (f x)) -> TypedList g xs -> ReadPrec (TypedList f xs)
+ Numeric.TypedList: typedListShowsPrec :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). (forall (x :: k). Int -> f x -> ShowS) -> Int -> TypedList f xs -> ShowS
+ Numeric.TypedList: typedListShowsPrecC :: forall (k :: Type) (c :: k -> Constraint) (f :: k -> Type) (xs :: [k]). All c xs => String -> (forall (x :: k). c x => Int -> f x -> ShowS) -> Int -> TypedList f xs -> ShowS
+ Numeric.TypedList: withTypedListReadPrec :: forall (k :: Type) (f :: k -> Type) (r :: Type). (forall (z :: Type). (forall (x :: k). f x -> z) -> ReadPrec z) -> (forall (xs :: [k]). TypedList f xs -> r) -> ReadPrec r
- Numeric.TypedList: concat :: TypedList f xs -> TypedList f ys -> TypedList f (xs ++ ys)
+ Numeric.TypedList: concat :: forall (k :: Type) (f :: k -> Type) (xs :: [k]) (ys :: [k]). TypedList f xs -> TypedList f ys -> TypedList f (xs ++ ys)
- Numeric.TypedList: cons :: f x -> TypedList f xs -> TypedList f (x :+ xs)
+ Numeric.TypedList: cons :: forall (k :: Type) (f :: k -> Type) (x :: k) (xs :: [k]). f x -> TypedList f xs -> TypedList f (x :+ xs)
- Numeric.TypedList: drop :: Dim n -> TypedList f xs -> TypedList f (Drop n xs)
+ Numeric.TypedList: drop :: forall (k :: Type) (n :: Nat) (f :: k -> Type) (xs :: [k]). Dim n -> TypedList f xs -> TypedList f (Drop n xs)
- Numeric.TypedList: head :: TypedList f xs -> f (Head xs)
+ Numeric.TypedList: head :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). TypedList f xs -> f (Head xs)
- Numeric.TypedList: init :: TypedList f xs -> TypedList f (Init xs)
+ Numeric.TypedList: init :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). TypedList f xs -> TypedList f (Init xs)
- Numeric.TypedList: last :: TypedList f xs -> f (Last xs)
+ Numeric.TypedList: last :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). TypedList f xs -> f (Last xs)
- Numeric.TypedList: length :: TypedList f xs -> Dim (Length xs)
+ Numeric.TypedList: length :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). TypedList f xs -> Dim (Length xs)
- Numeric.TypedList: map :: (forall a. f a -> g a) -> TypedList f xs -> TypedList g xs
+ Numeric.TypedList: map :: forall (k :: Type) (f :: k -> Type) (g :: k -> Type) (xs :: [k]). (forall (a :: k). f a -> g a) -> TypedList f xs -> TypedList g xs
- Numeric.TypedList: order :: TypedList f xs -> Dim (Length xs)
+ Numeric.TypedList: order :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). TypedList f xs -> Dim (Length xs)
- Numeric.TypedList: order' :: forall xs. RepresentableList xs => Dim (Length xs)
+ Numeric.TypedList: order' :: forall (k :: Type) (xs :: [k]). RepresentableList xs => Dim (Length xs)
- Numeric.TypedList: reverse :: TypedList f xs -> TypedList f (Reverse xs)
+ Numeric.TypedList: reverse :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). TypedList f xs -> TypedList f (Reverse xs)
- Numeric.TypedList: snoc :: TypedList f xs -> f x -> TypedList f (xs +: x)
+ Numeric.TypedList: snoc :: forall (k :: Type) (f :: k -> Type) (xs :: [k]) (x :: k). TypedList f xs -> f x -> TypedList f (xs +: x)
- Numeric.TypedList: splitAt :: Dim n -> TypedList f xs -> (TypedList f (Take n xs), TypedList f (Drop n xs))
+ Numeric.TypedList: splitAt :: forall (k :: Type) (n :: Nat) (f :: k -> Type) (xs :: [k]). Dim n -> TypedList f xs -> (TypedList f (Take n xs), TypedList f (Drop n xs))
- Numeric.TypedList: tail :: TypedList f xs -> TypedList f (Tail xs)
+ Numeric.TypedList: tail :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). TypedList f xs -> TypedList f (Tail xs)
- Numeric.TypedList: take :: Dim n -> TypedList f xs -> TypedList f (Take n xs)
+ Numeric.TypedList: take :: forall (k :: Type) (n :: Nat) (f :: k -> Type) (xs :: [k]). Dim n -> TypedList f xs -> TypedList f (Take n xs)
- Numeric.TypedList: types :: TypedList f xs -> TypeList xs
+ Numeric.TypedList: types :: forall (k :: Type) (f :: k -> Type) (xs :: [k]). TypedList f xs -> TypeList xs
Files
- dimensions.cabal +66/−57
- src/Data/Type/List.hs +232/−0
- src/Data/Type/List/InjectiveSnoc.hs +67/−0
- src/Data/Type/List/Internal.hs +27/−0
- src/Data/Type/Lits.hs +115/−0
- src/Numeric/Dim.hs +0/−446
- src/Numeric/Dimensions.hs +13/−17
- src/Numeric/Dimensions/Dim.hs +1084/−0
- src/Numeric/Dimensions/Dim.hs-boot +13/−0
- src/Numeric/Dimensions/Dims.hs +0/−440
- src/Numeric/Dimensions/Fold.hs +0/−334
- src/Numeric/Dimensions/Idx.hs +483/−0
- src/Numeric/Dimensions/Idxs.hs +0/−427
- src/Numeric/Tuple.hs +3/−10
- src/Numeric/Tuple/Lazy.hs +59/−132
- src/Numeric/Tuple/Strict.hs +60/−133
- src/Numeric/Type/Evidence.hs +0/−59
- src/Numeric/Type/List.hs +0/−222
- src/Numeric/TypedList.hs +357/−129
- test/Numeric/DimTest.hs +0/−86
- test/Numeric/Dimensions/DimTest.hs +159/−0
- test/Numeric/Dimensions/DimsTest.hs +0/−67
- test/Numeric/Dimensions/IdxTest.hs +165/−0
- test/Spec.hs +10/−9
dimensions.cabal view
@@ -1,65 +1,74 @@-name: dimensions-version: 1.0.1.1-cabal-version: >=1.22-build-type: Simple-license: BSD3-license-file: LICENSE-copyright: (c) Artem Chirkin-maintainer: chirkin@arch.ethz.ch-homepage: https://github.com/achirkin/easytensor#readme-synopsis: Safe type-level dimensionality for multidimensional data.-description:- Safe type-level dimensionality for multidimensional data.-category: Math, Geometry-author: Artem Chirkin+cabal-version: 1.12 -source-repository head- type: git- location: https://github.com/achirkin/easytensor.git- subdir: dimensions+-- This file has been generated from package.yaml by hpack version 0.31.1.+--+-- see: https://github.com/sol/hpack+--+-- hash: 982b8bf6393fdd487b646f7c7a3b258acba9501a6d106861757a3b4a49f3de82 +name: dimensions+version: 2.0.0.0+synopsis: Safe type-level dimensionality for multidimensional data.+description: Safe type-level dimensionality for multidimensional data. Please see the README on GitHub at <https://github.com/achirkin/easytensor#readme>+category: math, geometry+homepage: https://github.com/achirkin/easytensor#readme+bug-reports: https://github.com/achirkin/easytensor/issues+author: Artem Chirkin+maintainer: achirkin@users.noreply.github.com+copyright: Copyright: (c) 2019 Artem Chirkin+license: BSD3+license-file: LICENSE+build-type: Simple -flag unsafeindices- description:- Disable bound checks on Idx and Idxs types.- default: False+source-repository head+ type: git+ location: https://github.com/achirkin/easytensor+ subdir: dimensions +flag unsafeindices+ description: Disable bound checks on Idx and Idxs types.+ manual: True+ default: False library-- if flag(unsafeindices)- cpp-options: -DUNSAFE_INDICES- exposed-modules:- Numeric.Dim- Numeric.Tuple- Numeric.Tuple.Lazy- Numeric.Tuple.Strict- Numeric.Type.Evidence- Numeric.Type.List- Numeric.TypedList- Numeric.Dimensions- Numeric.Dimensions.Dims- Numeric.Dimensions.Idxs- Numeric.Dimensions.Fold- build-depends:- base >=4.9 && <5- default-language: Haskell2010- hs-source-dirs: src- ghc-options: -Wall-+ exposed-modules:+ Data.Type.List+ Data.Type.Lits+ Numeric.Dimensions+ Numeric.Dimensions.Dim+ Numeric.Dimensions.Idx+ Numeric.Tuple+ Numeric.Tuple.Lazy+ Numeric.Tuple.Strict+ Numeric.TypedList+ other-modules:+ Data.Type.List.InjectiveSnoc+ Data.Type.List.Internal+ hs-source-dirs:+ src+ ghc-options: -Wall -Wcompat -Wtabs -Wmissing-local-signatures -Wmissing-home-modules -Widentities+ build-depends:+ base >=4.10 && <5+ , constraints-deriving >=1 && <2+ , ghc+ if flag(unsafeindices)+ cpp-options: -DUNSAFE_INDICES+ default-language: Haskell2010 test-suite dimensions-test-- type: exitcode-stdio-1.0- main-is: Spec.hs- other-modules:- Numeric.DimTest- Numeric.Dimensions.DimsTest- build-depends:- base -any,- Cabal -any,- QuickCheck -any,- dimensions -any- default-language: Haskell2010- hs-source-dirs: test- ghc-options: -Wall+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ other-modules:+ Numeric.Dimensions.DimTest+ Numeric.Dimensions.IdxTest+ Paths_dimensions+ hs-source-dirs:+ test+ ghc-options: -Wall -Wcompat -Wtabs -Wmissing-local-signatures -Wmissing-home-modules -Widentities+ build-depends:+ Cabal+ , QuickCheck+ , base+ , constraints-deriving >=1 && <2+ , dimensions+ default-language: Haskell2010
+ src/Data/Type/List.hs view
@@ -0,0 +1,232 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilyDependencies #-}+{-# LANGUAGE TypeInType #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Type.List+-- Copyright : (c) Artem Chirkin+-- License : BSD3+--+-- Provides type-level operations on lists.+--+--+--------------------------------------------------------------------------------++module Data.Type.List+ ( -- * Basic operations+ type (++), type (+:), type (:+)+ , Empty, Cons, Snoc, Head+ , Tail, Last, Init, Concat+ , StripPrefix, StripSuffix+ , Reverse, Take, Drop, Length+ -- * Operations on elements+ , All, Map, Elem+ -- * Concatenation and its evidence+ , ConcatList, evStripSuffix, evStripPrefix, evConcat+ -- * Data.Typeable+ , inferTypeableCons+ ) where++import Data.Constraint ((:-) (..), Constraint, Dict (..))+import Data.Type.List.Internal (Snoc)+import Data.Type.Lits+import GHC.Base (Type)+import Type.Reflection+import Unsafe.Coerce (unsafeCoerce)++-- | Empty list, same as @'[]@.+type Empty = '[]++-- | Appending a list, represents an @Op@ counterpart of @(':)@.+type Cons (a :: k) (as :: [k])+ = a ': as++-- | Extract the first element of a list, which must be non-empty.+type family Head (xs :: [k]) :: k where+ Head ('[] :: [k]) = TypeError ( ListError k "Head: empty type-level list." )+ Head (x ': _) = x++-- | Extract the elements after the head of a list, which must be non-empty.+type family Tail (xs :: [k]) :: [k] where+ Tail ('[] :: [k]) = TypeError ( ListError k "Tail: empty type-level list." )+ Tail (_ ': xs) = xs++-- | Extract the last element of a list, which must be non-empty.+type family Last (xs :: [k]) :: k where+ Last ('[] :: [k]) = TypeError ( ListError k "Last: empty type-level list." )+ Last '[x] = x+ Last (_ ': xs) = Last xs++-- | Extract all but last elements of a list, which must be non-empty.+type family Init (xs :: [k]) :: [k] where+ Init ('[] :: [k]) = TypeError ( ListError k "Init: empty type-level list." )+ Init '[x] = '[]+ Init (x ': xs) = x ': Init xs++-- | @Take n xs@ returns the prefix of a list of length @max n (length xs)@.+type family Take (n :: Nat) (xs :: [k]) :: [k] where+ Take 0 _ = '[]+ Take n (x ': xs) = x ': Take (n - 1) xs+ Take _ '[] = '[]++-- | @Drop n xs@ drops up to @n@ elements of @xs@.+type family Drop (n :: Nat) (xs :: [k]) :: [k] where+ Drop 0 xs = xs+ Drop n (_ ': xs) = Drop (n - 1) xs+ Drop _ '[] = '[]++-- | Append two lists.+type family Concat (as :: [k]) (bs :: [k]) :: [k] where+ Concat '[] bs = bs+ Concat as '[] = as+ Concat (a ': as) bs = a ': Concat as bs++-- | Remove prefix @as@ from a list @asbs@ if @as@ is a prefix; fail otherwise.+type family StripPrefix (as :: [k]) (asbs :: [k]) :: [k] where+ StripPrefix as as = '[]+ StripPrefix '[] asbs = asbs+ StripPrefix (a ': as) (a ': asbs) = StripPrefix as asbs+ StripPrefix (a ': as) (b ': asbs)+ = TypeError+ ( 'Text "StripPrefix: the first argument is not a prefix of the second."+ ':$$:+ 'Text "Failed prefix: " ':<>: 'ShowType (a ': as)+ ':$$:+ 'Text "Second argument: " ':<>: 'ShowType (b ': asbs)+ )+ StripPrefix (a ': as) '[]+ = TypeError+ ( 'Text "StripPrefix: the first argument is longer than the second."+ ':$$:+ 'Text "Failed prefix: " ':<>: 'ShowType (a ': as)+ ':$$:+ 'Text "The reduced second argument is empty."+ )++-- | Remove suffix @bs@ from a list @asbs@ if @bs@ is a suffix; fail otherwise.+type family StripSuffix (bs :: [k]) (asbs :: [k]) :: [k] where+ StripSuffix bs bs = '[]+ StripSuffix '[] asbs = asbs+ StripSuffix (a ': bs) (b ': bs)+ = TypeError+ ( 'Text "StripSuffix: the first argument is not a suffix of the second."+ ':$$:+ 'Text "Failed match: "+ ':<>: 'ShowType ((a ': bs) ~ (b ': bs))+ )+ StripSuffix (b ': bs) '[]+ = TypeError+ ( 'Text "StripSuffix: the first argument is longer than the second."+ ':$$:+ 'Text "Failed suffix: " ':<>: 'ShowType (b ': bs)+ ':$$:+ 'Text "The reduced second argument is empty."+ )+ StripSuffix bs (a ': asbs) = a ': StripSuffix bs asbs++-- | Returns the elements of a list in reverse order.+type family Reverse (xs :: [k]) :: [k] where+ -- Note: the goal is not to write a fast implementation,+ -- but make it easier for the type checker to simplify things.+ -- This is only going to be executed during compile time,+ -- so there is no real performance impact.+ Reverse '[] = '[]+ Reverse (x ': xs) = Snoc (Reverse xs) x++-- | Number of elements in a list.+type family Length (xs :: [k]) :: Nat where+ Length '[] = 0+ Length (x ': xs) = Length xs + 1++-- | Synonym for a type-level @Cons@.+type (a :: k) :+ (as :: [k]) = a ': as+infixr 5 :+++-- | Synonym for a type-level @Snoc@.+type (ns :: [k]) +: (n :: k) = Snoc ns n+infixl 6 +:++-- | Infix-style synonym for concatenation+type (as :: [k]) ++ (bs :: [k]) = Concat as bs+infixr 5 ++++-- | All elements of a type list must satisfy the same constraint.+type family All (f :: k -> Constraint) (xs :: [k]) :: Constraint where+ All _ '[] = ()+ All f (x ': xs) = (f x, All f xs)++-- | Map a functor over the elements of a type list.+type family Map (f :: a -> b) (xs :: [a]) :: [b] where+ Map f '[] = '[]+ Map f (x ': xs) = f x ': Map f xs++-- | Check if an item is a member of a list.+type family Elem (x :: k) (xs :: [k]) :: Constraint where+ Elem x (x ': xs) = ()+ Elem x (_ ': xs) = Elem x xs++type ListError k t+ = 'Text t ':$$:+ ( 'Text "Type-level error occured when operating on a list of kind "+ ':<>: 'ShowType [k] ':<>: 'Text "."+ )++-- | Represent a triple of lists forming a relation @(as ++ bs) ~ asbs@+type ConcatList (as :: [k]) (bs :: [k]) (asbs :: [k]) =+ ( asbs ~ Concat as bs+ , as ~ StripSuffix bs asbs+ , bs ~ StripPrefix as asbs+ )++-- | Derive @ConcatList@ given @Concat@+evConcat :: forall (k :: Type) (as :: [k]) (bs :: [k]) (asbs :: [k])+ . (asbs ~ Concat as bs) :- ConcatList as bs asbs+evConcat = Sub $ unsafeCoerce+ ( Dict :: Dict+ ( asbs ~ Concat as bs+ , as ~ as+ , bs ~ bs+ )+ )++-- | Derive @ConcatList@ given @StripSuffix@+evStripSuffix :: forall (k :: Type) (as :: [k]) (bs :: [k]) (asbs :: [k])+ . (as ~ StripSuffix bs asbs) :- ConcatList as bs asbs+evStripSuffix = Sub $ unsafeCoerce+ ( Dict :: Dict+ ( asbs ~ asbs+ , as ~ StripSuffix bs asbs+ , bs ~ bs+ )+ )++-- | Derive @ConcatList@ given @StripPrefix@+evStripPrefix :: forall (k :: Type) (as :: [k]) (bs :: [k]) (asbs :: [k])+ . (bs ~ StripPrefix as asbs) :- ConcatList as bs asbs+evStripPrefix = Sub $ unsafeCoerce+ ( Dict :: Dict+ ( asbs ~ asbs+ , as ~ as+ , bs ~ StripPrefix as asbs+ )+ )++-- | Given a @Typeable@ list, infer this constraint for its parts.+inferTypeableCons :: forall (k :: Type) (ys :: [k]) (x :: k) (xs :: [k])+ . (Typeable ys, ys ~ (x ': xs))+ => Dict (Typeable x, Typeable xs)+inferTypeableCons = case typeRep @ys of+ App _ xRep `App` xsRep+ -> case ( withTypeable xRep (Dict @(Typeable x))+ , withTypeable xsRep (Dict @(Typeable xs))+ ) of+ (Dict, Dict) -> Dict
+ src/Data/Type/List/InjectiveSnoc.hs view
@@ -0,0 +1,67 @@+{-# OPTIONS_GHC -fobject-code #-}+{-# OPTIONS_HADDOCK hide, prune #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Type.List.InjectiveSnoc+-- Copyright : (c) Artem Chirkin+-- License : BSD3+--+-- A small core plugin to make GHC think that @Snoc@ is injective+--+--+--------------------------------------------------------------------------------+module Data.Type.List.InjectiveSnoc ( plugin ) where+++import CoAxiom (CoAxBranch (..), CoAxiom (..), mapAccumBranches)+import Data.Maybe (fromMaybe)+import GhcPlugins++-- NB: check out+-- https://github.com/ghc/ghc/blob/bf73419518ca550e85188616f860961c7e2a336b/compiler/typecheck/TcTypeNats.hs+-- for further ideas.+-- Maybe, I can use BuiltInSynFamily to do a lot of super cool stuff!++-- | A small core plugin to make GHC think that @Snoc@ is injective+plugin :: Plugin+plugin = defaultPlugin+ { installCoreToDos =+ const $ pure . (CoreDoPluginPass "InjectiveSnoc" injectiveSnocPass :)+ }++injectiveSnocPass :: ModGuts -> CoreM ModGuts+injectiveSnocPass = pure . modSnocFam updateSnocFam++modSnocFam :: (TyCon -> TyCon) -> ModGuts -> ModGuts+modSnocFam f guts = guts {mg_tcs = map g (mg_tcs guts)}+ where+ g tc+ | nameOccName (tyConName tc) == mkTcOcc "Snoc" = f tc+ | otherwise = tc++updateSnocFam :: TyCon -> TyCon+updateSnocFam tc = fromMaybe tc $ do+ axiom <- isClosedSynFamilyTyConWithAxiom_maybe tc+ let newAxiom = axiom+ { co_ax_tc = newTc+ , co_ax_branches = mapAccumBranches f (co_ax_branches axiom)+ }+ f _ b = b { cab_rhs = repTc (cab_rhs b) }+ repTc t = case splitTyConApp_maybe t of+ Just (c, ts)+ | nameOccName (tyConName c) == mkTcOcc "Snoc"+ -> mkTyConApp newTc $ map repTc ts+ | otherwise+ -> mkTyConApp c $ map repTc ts+ Nothing+ -> t+ newTc = mkFamilyTyCon+ (tyConName tc) -- Name+ (tyConBinders tc) -- [TyConBinder]+ (tyConResKind tc) -- Kind+ (famTcResVar tc) -- Maybe Name+ (ClosedSynFamilyTyCon (Just newAxiom)) -- FamTyConFlav+ (tyConAssoc_maybe tc) -- Maybe Class+ -- Injectivity copied from a dummy injective TF with the same head+ (Injective [True, True, True]) -- Injectivity+ return newTc
+ src/Data/Type/List/Internal.hs view
@@ -0,0 +1,27 @@+{-# OPTIONS_GHC -fobject-code #-}+{-# OPTIONS_GHC -fplugin Data.Type.List.InjectiveSnoc #-}+{-# OPTIONS_HADDOCK hide, prune #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE TypeFamilyDependencies #-}+{-# LANGUAGE TypeOperators #-}++{-# LANGUAGE TypeInType #-}+{-# LANGUAGE UndecidableInstances #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Type.List.Internal+-- Copyright : (c) Artem Chirkin+-- License : BSD3+--+-- Thanks to @Data.Type.List.InjectiveSnoc@, @Snoc@ appears to be injective+-- for an oustide viewer.+--+--+--------------------------------------------------------------------------------+module Data.Type.List.Internal ( Snoc ) where++-- | Appending a list on the other side.+type family Snoc (xs :: [k]) (x :: k) = (ys :: [k]) where+ Snoc (x ': xs) y = x ': Snoc xs y+ Snoc '[] y = '[y]
+ src/Data/Type/Lits.hs view
@@ -0,0 +1,115 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE ExplicitForAll #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+#if __GLASGOW_HASKELL__ >= 806+{-# LANGUAGE NoStarIsType #-}+#endif+++{-# LANGUAGE FlexibleContexts #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Type.List+-- Copyright : (c) Artem Chirkin+-- License : BSD3+--+-- A Mixture of `GHC.TypeLits` and `GHC.TypeNats` with @Nat@s represented as+-- @Natural@ at runtime, plus some helper functions of our own.+--+--------------------------------------------------------------------------------++module Data.Type.Lits+ ( -- * Kinds+ TN.Nat, TL.Symbol+ -- * Linking type and value level+ , TN.KnownNat, TN.natVal, TN.natVal'+ , TL.KnownSymbol, TL.symbolVal, TL.symbolVal'+ , TN.SomeNat(..), TL.SomeSymbol(..)+ , TN.someNatVal, TL.someSymbolVal+ , TN.sameNat, TL.sameSymbol+ -- * Functions on type literals+ , type (+), type (*), type (^), type (-)+ , type TN.Div, type TN.Mod, type TN.Log2+ , TL.AppendSymbol, ShowNat+ , TN.CmpNat, TL.CmpSymbol, type (<=)+ , SOrdering (..), cmpNat, cmpSymbol+ -- * User-defined type errors+ , TL.TypeError+ , TL.ErrorMessage(..)+ ) where+++import Data.Kind (Constraint, Type)+import qualified GHC.TypeLits as TL+import GHC.TypeNats (type (*), type (+), type (-), type (^))+import qualified GHC.TypeNats as TN+import Unsafe.Coerce (unsafeCoerce)+++++-- | Convert a type-level @Nat@ into a type-level @Symbol@.+type family ShowNat (n :: TN.Nat) :: TL.Symbol where+ -- lol+ ShowNat 0 = "0"+ ShowNat 1 = "1"+ ShowNat 2 = "2"+ ShowNat 3 = "3"+ ShowNat 4 = "4"+ ShowNat 5 = "5"+ ShowNat 6 = "6"+ ShowNat 7 = "7"+ ShowNat 8 = "8"+ ShowNat 9 = "9"+ ShowNat d = TL.AppendSymbol (ShowNat (TN.Div d 10)) (ShowNat (TN.Mod d 10))+++-- | Singleton-style version of `Ordering`.+-- Pattern-match againts its constructor to witness the result of+-- type-level comparison.+data SOrdering :: Ordering -> Type where+ SLT :: SOrdering 'LT+ SEQ :: SOrdering 'EQ+ SGT :: SOrdering 'GT++-- | Pattern-match against the result of this function to get the evidence+-- of comparing type-level Nats.+cmpNat :: forall (a :: TN.Nat) (b :: TN.Nat) (proxy :: TN.Nat -> Type)+ . (TN.KnownNat a, TN.KnownNat b)+ => proxy a -> proxy b -> SOrdering (TN.CmpNat a b)+cmpNat a b+ = case compare (TN.natVal a) (TN.natVal b) of+ LT -> unsafeCoerce SLT+ EQ -> unsafeCoerce SEQ+ GT -> unsafeCoerce SGT+{-# INLINE cmpNat #-}++-- | Pattern-match against the result of this function to get the evidence+-- of comparing type-level Symbols.+cmpSymbol :: forall (a :: TL.Symbol) (b :: TL.Symbol) (proxy :: TL.Symbol -> Type)+ . (TL.KnownSymbol a, TL.KnownSymbol b)+ => proxy a -> proxy b -> SOrdering (TL.CmpSymbol a b)+cmpSymbol a b+ = case compare (TL.symbolVal a) (TL.symbolVal b) of+ LT -> unsafeCoerce SLT+ EQ -> unsafeCoerce SEQ+ GT -> unsafeCoerce SGT+{-# INLINE cmpSymbol #-}++-- | Comparison of type-level naturals, as a constraint.+type (<=) (a :: TN.Nat) (b :: TN.Nat) = LE a b (TN.CmpNat a b)++type family LE (a :: TN.Nat) (b :: TN.Nat) (r :: Ordering) :: Constraint where+ LE _ _ 'LT = ()+ LE _ _ 'EQ = ()+ LE a b 'GT = TL.TypeError+ ('TL.Text "Cannot deduce type-level Nat relation: "+ 'TL.:<>: 'TL.ShowType a+ 'TL.:<>: 'TL.Text " <= "+ 'TL.:<>: 'TL.ShowType b+ )
− src/Numeric/Dim.hs
@@ -1,446 +0,0 @@-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE ExplicitNamespaces #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE MagicHash #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE RoleAnnotations #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE Strict #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE ViewPatterns #-}--------------------------------------------------------------------------------- |--- Module : Numeric.Dim--- Copyright : (c) Artem Chirkin--- License : BSD3------ Maintainer : chirkin@arch.ethz.ch------ This module is based on `GHC.TypeLits` and re-exports its functionality.--- It provides `KnownDim` class that is similar to `KnownNat`, but keeps--- `Word`s instead of `Integer`s;--- Also it provides `Dim` data type serving as a singleton--- suitable for recovering an instance of the `KnownDim` class.--- A set of utility functions provide inference functionality, so--- that `KnownDim` can be preserved over some type-level operations.----------------------------------------------------------------------------------module Numeric.Dim- ( -- * Type level numbers that can be unknown.- XNat (..), XN, N, XNatType (..)- -- * Term level dimension- , Dim (Dim, D, Dn, Dx), SomeDim- , KnownDim (..), KnownXNatType (..)- , dimVal, dimVal', someDimVal- , sameDim, sameDim'- , compareDim, compareDim'- , constrain, constrainBy, relax- -- * Simple Dim arithmetics- --- -- The functions below create singleton values that work as a witness- -- of `KnownDim` instance for type-level Nat operations.- -- For example, to show that @(a + b)@ is a @KnownDim@, one writes:- --- -- > case plusDim dA dB of- -- > D -> ... -- here we know KnownDim ( a + b )- --- -- There is a bug and a feature in these functions though:- -- they are implemented in terms of @Num Word@, which means that- -- their results are subject to integer overflow.- -- The good side is the confidence that they behave exactly as- -- their @Word@ counterparts.- , plusDim, minusDim, minusDimM, timesDim, powerDim- -- * Re-export part of `GHC.TypeLits` for convenience- , TL.Nat, TL.CmpNat, type (TL.+), type (TL.-), type (TL.*), type (TL.^)- , MinDim, FixedDim, inferDimLE- -- * Inferring kind of type-level dimension- , KnownDimKind (..), DimKind (..)- ) where---import Data.Type.Bool-import Data.Type.Equality-import GHC.Base (Type)-import GHC.Exts (Constraint, Proxy#, proxy#, unsafeCoerce#)-import GHC.TypeLits as TL--import Numeric.Type.Evidence----- | Either known or unknown at compile-time natural number-data XNat = XN Nat | N Nat--- | Unknown natural number, known to be not smaller than the given Nat-type XN (n::Nat) = 'XN n--- | Known natural number-type N (n::Nat) = 'N n---- | Find out whether @XNat@ is of known or constrained type.-data XNatType :: XNat -> Type where- -- | Given @XNat@ is known- Nt :: XNatType ('N n)- -- | Given @XNat@ is constrained unknown- XNt :: XNatType ('XN m)---- | Same as `SomeNat`-type SomeDim = Dim ('XN 0)---- | Singleton type to store type-level dimension value.------ On the one hand, it can be used to let type-inference system know--- relations between type-level naturals.--- On the other hand, this is just a newtype wrapper on the @Word@ type.------ Usually, the type parameter of @Dim@ is either @Nat@ or @XNat@.--- If dimensionality of your data is known in advance, use @Nat@;--- if you know the size of some dimensions, but do not know the size--- of others, use @XNat@s to represent them.-newtype Dim (x :: k) = DimSing Word--- Starting from GHC 8.2, compiler supports specifying lists of complete--- pattern synonyms.-#if __GLASGOW_HASKELL__ >= 802-{-# COMPLETE D #-}-{-# COMPLETE Dn, Dx #-}-{-# COMPLETE Dim #-}-#endif----- | Independently of the kind of type-level number,--- construct an instance of `KnownDim` from it.------ Match against this pattern to bring `KnownDim` instance into scope--- when you don't know the kind of the @Dim@ parameter.-pattern Dim :: forall (n :: k) . () => KnownDim n => Dim n-pattern Dim <- (dimEv -> E)- where- Dim = dim @_ @n----- | Same as @Dim@ pattern, but constrained to @Nat@ kind.-pattern D :: forall (n :: Nat) . () => KnownDim n => Dim n-pattern D <- (dimEv -> E)- where- D = dim @_ @n---- | Statically known `XNat`-pattern Dn :: forall (xn :: XNat) . KnownXNatType xn- => forall (n :: Nat) . (KnownDim n, xn ~ 'N n) => Dim n -> Dim xn-pattern Dn k <- (dimXNEv (xNatType @xn) -> PatN k)- where- Dn k = unsafeCoerce# k---- | `XNat` that is unknown at compile time.--- Same as `SomeNat`, but for a dimension:--- Hide dimension size inside, but allow specifying its minimum possible value.-pattern Dx :: forall (xn :: XNat) . KnownXNatType xn- => forall (n :: Nat) (m :: Nat)- . (KnownDim n, MinDim m n, xn ~ 'XN m) => Dim n -> Dim xn-pattern Dx k <- (dimXNEv (xNatType @xn) -> PatXN k)- where- Dx k = unsafeCoerce# k---- | This class provides the `Dim` associated with a type-level natural.-class KnownDim (n :: k) where- -- | Get value of type-level dim at runtime.- --- -- Note, this function is supposed to be used with @TypeApplications@,- -- and the @KnownDim@ class has varying kind of the parameter;- -- thus, the function has two type paremeters (kind and type of @n@).- -- For example, you can type:- --- -- >>>:set -XTypeApplications- -- >>>:set -XDataKinds- -- >>>:t dim @Nat @3- -- dim @Nat @3 :: Dim 3- --- -- >>>:set -XTypeOperators- -- >>>:t dim @_ @(13 - 6)- -- dim @_ @(13 - 6) :: Dim 7- --- --- -- >>>:t dim @_ @(N 17)- -- dim @_ @(N 17) :: Dim (N 17)- --- dim :: Dim n----- | Find out the type of `XNat` constructor-class KnownXNatType (n :: XNat) where- -- | Pattern-match against this to out the type of `XNat` constructor- xNatType :: XNatType n--instance KnownXNatType ('N n) where- xNatType = Nt- {-# INLINE xNatType #-}--instance KnownXNatType ('XN n) where- xNatType = XNt- {-# INLINE xNatType #-}----- | Similar to `natVal` from `GHC.TypeLits`, but returns `Word`.-dimVal :: Dim (x :: k) -> Word-dimVal = unsafeCoerce#-{-# INLINE dimVal #-}---- | Similar to `natVal` from `GHC.TypeLits`, but returns `Word`.-dimVal' :: forall n . KnownDim n => Word-dimVal' = unsafeCoerce# (dim @_ @n)-{-# INLINE dimVal' #-}---- | Friendly error message if `m <= n` constraint is not satisfied.--- Use this type family instead of @(<=)@ if possible--- or try `inferDimLE` function as the last resort.-type family MinDim (m :: Nat) (n :: Nat) :: Constraint where- MinDim m n =- If (CmpNat m n == 'GT)- (TypeError- ('Text "Minimum Dim size constraint ("- ':<>: 'ShowType m- ':<>: 'Text " <= "- ':<>: 'ShowType n- ':<>: 'Text ") is not satisfied."- ':$$: 'Text "Minimum Dim: " ':<>: 'ShowType m- ':$$: 'Text " Actual Dim: " ':<>: 'ShowType n- ) :: Constraint- )- (m <= n)---- | Constraints given by an XNat type on possible values of a Nat hidden inside.-type family FixedDim (x :: XNat) (n :: Nat) :: Constraint where- FixedDim ('N a) b = a ~ b- FixedDim ('XN m) b = MinDim m b--instance {-# OVERLAPPABLE #-} KnownNat n => KnownDim n where- {-# INLINE dim #-}- dim = DimSing (fromInteger (natVal' (proxy# :: Proxy# n)))--instance {-# OVERLAPPING #-} KnownDim 0 where- { {-# INLINE dim #-}; dim = DimSing 0 }-instance {-# OVERLAPPING #-} KnownDim 1 where- { {-# INLINE dim #-}; dim = DimSing 1 }-instance {-# OVERLAPPING #-} KnownDim 2 where- { {-# INLINE dim #-}; dim = DimSing 2 }-instance {-# OVERLAPPING #-} KnownDim 3 where- { {-# INLINE dim #-}; dim = DimSing 3 }-instance {-# OVERLAPPING #-} KnownDim 4 where- { {-# INLINE dim #-}; dim = DimSing 4 }-instance {-# OVERLAPPING #-} KnownDim 5 where- { {-# INLINE dim #-}; dim = DimSing 5 }-instance {-# OVERLAPPING #-} KnownDim 6 where- { {-# INLINE dim #-}; dim = DimSing 6 }-instance {-# OVERLAPPING #-} KnownDim 7 where- { {-# INLINE dim #-}; dim = DimSing 7 }-instance {-# OVERLAPPING #-} KnownDim 8 where- { {-# INLINE dim #-}; dim = DimSing 8 }-instance {-# OVERLAPPING #-} KnownDim 9 where- { {-# INLINE dim #-}; dim = DimSing 9 }-instance {-# OVERLAPPING #-} KnownDim 10 where- { {-# INLINE dim #-}; dim = DimSing 10 }-instance {-# OVERLAPPING #-} KnownDim 11 where- { {-# INLINE dim #-}; dim = DimSing 11 }-instance {-# OVERLAPPING #-} KnownDim 12 where- { {-# INLINE dim #-}; dim = DimSing 12 }-instance {-# OVERLAPPING #-} KnownDim 13 where- { {-# INLINE dim #-}; dim = DimSing 13 }-instance {-# OVERLAPPING #-} KnownDim 14 where- { {-# INLINE dim #-}; dim = DimSing 14 }-instance {-# OVERLAPPING #-} KnownDim 15 where- { {-# INLINE dim #-}; dim = DimSing 15 }-instance {-# OVERLAPPING #-} KnownDim 16 where- { {-# INLINE dim #-}; dim = DimSing 16 }-instance {-# OVERLAPPING #-} KnownDim 17 where- { {-# INLINE dim #-}; dim = DimSing 17 }-instance {-# OVERLAPPING #-} KnownDim 18 where- { {-# INLINE dim #-}; dim = DimSing 18 }-instance {-# OVERLAPPING #-} KnownDim 19 where- { {-# INLINE dim #-}; dim = DimSing 19 }-instance {-# OVERLAPPING #-} KnownDim 20 where- { {-# INLINE dim #-}; dim = DimSing 20 }--instance KnownDim n => KnownDim ('N n) where- {-# INLINE dim #-}- dim = unsafeCoerce# (dim @Nat @n)---- | Similar to `someNatVal` from `GHC.TypeLits`.-someDimVal :: Word -> SomeDim-someDimVal = unsafeCoerce#-{-# INLINE someDimVal #-}----- | Change the minimum allowed size of a @Dim (XN x)@,--- while testing if the value inside satisfies it.-constrain :: forall (m :: Nat) x . KnownDim m- => Dim x -> Maybe (Dim (XN m))-constrain (DimSing x) | dimVal' @m > x = Nothing- | otherwise = Just (unsafeCoerce# x)-{-# INLINE constrain #-}---- | `constrain` with explicitly-passed constraining @Dim@--- to avoid @AllowAmbiguousTypes@.-constrainBy :: forall m x . Dim m -> Dim x -> Maybe (Dim (XN m))-constrainBy D = constrain @m-#if __GLASGOW_HASKELL__ < 802-constrainBy _ = error "Dim: Impossible pattern."-#endif---- | Decrease minimum allowed size of a @Dim (XN x)@.-relax :: forall (m :: Nat) (n :: Nat) . (MinDim m n) => Dim (XN n) -> Dim (XN m)-relax = unsafeCoerce#-{-# INLINE relax #-}----- | We either get evidence that this function--- was instantiated with the same type-level numbers, or Nothing.------ Note, this function works on @Nat@-indexed dimensions only,--- because @Dim (XN x)@ does not have runtime evidence to infer @x@--- and `KnownDim x` does not imply `KnownDim (XN x)`.-sameDim :: forall (x :: Nat) (y :: Nat)- . Dim x -> Dim y -> Maybe (Evidence (x ~ y))-sameDim (DimSing a) (DimSing b)- | a == b = Just (unsafeCoerce# (E @(x ~ x)))- | otherwise = Nothing-{-# INLINE sameDim #-}---- | We either get evidence that this function--- was instantiated with the same type-level numbers, or Nothing.-sameDim' :: forall (x :: Nat) (y :: Nat) p q- . (KnownDim x, KnownDim y)- => p x -> q y -> Maybe (Evidence (x ~ y))-sameDim' _ _ = sameDim (dim @Nat @x) (dim @Nat @y)-{-# INLINE sameDim' #-}---- | Ordering of dimension values.-compareDim :: Dim a -> Dim b -> Ordering-compareDim = unsafeCoerce# (compare :: Word -> Word -> Ordering)-{-# INLINE compareDim #-}----- | Ordering of dimension values.-compareDim' :: forall a b p q- . (KnownDim a, KnownDim b) => p a -> q b -> Ordering-compareDim' _ _ = compareDim (dim @_ @a) (dim @_ @b)-{-# INLINE compareDim' #-}---instance Eq (Dim (n :: Nat)) where- _ == _ = True- {-# INLINE (==) #-}--instance Eq (Dim (x :: XNat)) where- DimSing a == DimSing b = a == b- {-# INLINE (==) #-}--instance Ord (Dim (n :: Nat)) where- compare _ _ = EQ- {-# INLINE compare #-}--instance Ord (Dim (x :: XNat)) where- compare = compareDim- {-# INLINE compare #-}--instance Show (Dim x) where- showsPrec p = showsPrec p . dimVal- {-# INLINE showsPrec #-}--instance KnownDim m => Read (Dim ('XN m)) where- readsPrec p xs = do (a,ys) <- readsPrec p xs- case constrain (someDimVal a) of- Nothing -> []- Just n -> [(n,ys)]-----plusDim :: Dim n -> Dim m -> Dim (n + m)-plusDim (DimSing a) (DimSing b) = unsafeCoerce# (a + b)-{-# INLINE plusDim #-}--minusDim :: MinDim m n => Dim n -> Dim m -> Dim (n - m)-minusDim (DimSing a) (DimSing b) = unsafeCoerce# (a - b)-{-# INLINE minusDim #-}--minusDimM :: Dim n -> Dim m -> Maybe (Dim (n - m))-minusDimM (DimSing a) (DimSing b)- | a >= b = Just (unsafeCoerce# (a - b))- | otherwise = Nothing-{-# INLINE minusDimM #-}--timesDim :: Dim n -> Dim m -> Dim ((TL.*) n m)-timesDim (DimSing a) (DimSing b) = unsafeCoerce# (a * b)-{-# INLINE timesDim #-}--powerDim :: Dim n -> Dim m -> Dim ((TL.^) n m)-powerDim (DimSing a) (DimSing b) = unsafeCoerce# (a ^ b)-{-# INLINE powerDim #-}----- | @MinDim@ implies @(<=)@, but this fact is not so clear to GHC.--- This function assures the type system that the relation takes place.-inferDimLE :: forall m n . MinDim m n => Evidence (m <= n)-inferDimLE = unsafeCoerce# (E @(n <= n))----- | GADT to support `KnownDimKind` type class.--- Match against its constructors to know if @k@ is @Nat@ or @XNat@-data DimKind :: Type -> Type where- -- | Working on @Nat@.- DimNat :: DimKind Nat- -- | Working on @XNat@.- DimXNat :: DimKind XNat---- | Figure out whether the type-level dimension is `Nat` or `XNat`.--- Useful for generalized inference functions.-class KnownDimKind k where- dimKind :: DimKind k--instance KnownDimKind Nat where- dimKind = DimNat--instance KnownDimKind XNat where- dimKind = DimXNat-------------------------------------------------------------------------------------- | This function does GHC's magic to convert user-supplied `dim` function--- to create an instance of `KnownDim` typeclass at runtime.--- The trick is taken from Edward Kmett's reflection library explained--- in https://www.schoolofhaskell.com/user/thoughtpolice/using-reflection-reifyDim :: forall r d . Dim d -> (KnownDim d => r) -> r-reifyDim d k = unsafeCoerce# (MagicDim k :: MagicDim d r) d-{-# INLINE reifyDim #-}-newtype MagicDim d r = MagicDim (KnownDim d => r)--dimEv :: Dim d -> Evidence (KnownDim d)-dimEv d = reifyDim d E-{-# INLINE dimEv #-}--data PatXDim (xn :: XNat) where- PatN :: KnownDim n => Dim n -> PatXDim ('N n)- PatXN :: (KnownDim n, MinDim m n) => Dim n -> PatXDim ('XN m)--dimXNEv :: forall (xn :: XNat) . XNatType xn -> Dim xn -> PatXDim xn-dimXNEv Nt (DimSing k) = reifyDim dd (PatN dd)- where- dd = DimSing @Nat @_ k-dimXNEv XNt xn@(DimSing k) = reifyDim dd (f dd xn)- where- dd = DimSing @Nat @_ k- f :: forall (d :: Nat) (m :: Nat)- . KnownDim d => Dim d -> Dim ('XN m) -> PatXDim ('XN m)- f d _ = case ( unsafeCoerce# (E @((CmpNat m m == 'GT) ~ 'False, m <= m))- :: Evidence ((CmpNat m d == 'GT) ~ 'False, m <= d)- ) of- E -> PatXN d-{-# INLINE dimXNEv #-}
src/Numeric/Dimensions.hs view
@@ -4,29 +4,25 @@ -- Copyright : (c) Artem Chirkin -- License : BSD3 ----- Maintainer : chirkin@arch.ethz.ch -- -- Provides a set of data types to define and traverse through multiple dimensions.--- The core types are `Dims ds` and `Idxs ds`, which fix dimension sizes at compile time.+-- The core types are `Dims ds` and `Idxs ds`,+-- which fix dimension sizes at compile time. ----- Lower indices go first, i.e. assumed enumeration--- is i = i1 + i2*n1 + i3*n1*n2 + ... + ik*n1*n2*...*n(k-1).--- This is also to encourage column-first matrix enumeration and array layout.+-- Higher indices go first, i.e. assumed enumeration+-- is i = i1*n1*n2*...*n(k-1) + ... + i(k-2)*n1*n2 + i(k-1)*n1 + ik+-- This corresponds to row-first layout of matrices and multidimenional arrays. -- ----------------------------------------------------------------------------- module Numeric.Dimensions- ( module Numeric.Dim- , module Numeric.Dimensions.Dims- , module Numeric.Dimensions.Idxs- , module Numeric.Dimensions.Fold- , module Numeric.Type.Evidence- , module Numeric.Type.List+ ( module Numeric.Dimensions.Dim+ , module Numeric.Dimensions.Idx+ , module Data.Type.List+ , module Data.Constraint ) where -import Numeric.Dim-import Numeric.Dimensions.Dims-import Numeric.Dimensions.Idxs-import Numeric.Dimensions.Fold-import Numeric.Type.Evidence-import Numeric.Type.List+import Data.Constraint ((:-) (..), Dict (..), mapDict, (\\))+import Data.Type.List+import Numeric.Dimensions.Dim+import Numeric.Dimensions.Idx
+ src/Numeric/Dimensions/Dim.hs view
@@ -0,0 +1,1084 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RoleAnnotations #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilyDependencies #-}+{-# LANGUAGE TypeInType #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE UndecidableSuperClasses #-}+{-# LANGUAGE ViewPatterns #-}+#if __GLASGOW_HASKELL__ >= 806+{-# LANGUAGE NoStarIsType #-}+#endif+-----------------------------------------------------------------------------+-- |+-- Module : Numeric.Dimensions.Dim+-- Copyright : (c) Artem Chirkin+-- License : BSD3+--+-- This module provides `KnownDim` class that is similar to `KnownNat` from `GHC.TypeNats`,+-- but keeps `Word`s instead of `Natural`s;+-- Also it provides `Dim` data type serving as a singleton+-- suitable for recovering an instance of the `KnownDim` class.+-- A set of utility functions provide inference functionality, so+-- that `KnownDim` can be preserved over some type-level operations.+--+-- Provides a data type @Dims ds@ to keep dimension sizes+-- for multiple-dimensional data.+-- Higher indices go first, i.e. assumed enumeration+-- is i = i1*n1*n2*...*n(k-1) + ... + i(k-2)*n1*n2 + i(k-1)*n1 + ik+-- This corresponds to row-first layout of matrices and multidimenional arrays.+--+-----------------------------------------------------------------------------++module Numeric.Dimensions.Dim+ ( -- * @Dim@ -- a @Nat@-indexed dimension+ -- ** Type level numbers that can be unknown.+ XNat (..), XN, N, XNatType (..)+ -- ** Term level dimension+ , Dim ( D, Dn, Dx+ , D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13+ , D14, D15, D16, D17, D18, D19, D20, D21, D22, D23, D24, D25+ )+ , SomeDim+ , KnownDim (..), BoundedDim (..), minDim, KnownXNatType (..), FixedDim+ , dimVal, dimVal', typeableDim, someDimVal+ , sameDim, sameDim'+ , compareDim, compareDim'+ , constrainBy, relax+ -- * Simple Dim arithmetics+ --+ -- The functions below create singleton values that work as a witness+ -- of `KnownDim` instance for type-level Nat operations.+ -- For example, to show that @(a + b)@ is a @KnownDim@, one writes:+ --+ -- > case plusDim dA dB of+ -- > D -> ... -- here we know KnownDim ( a + b )+ --+ -- There is a bug and a feature in these functions though:+ -- they are implemented in terms of @Num Word@, which means that+ -- their results are subject to integer overflow.+ -- The good side is the confidence that they behave exactly as+ -- their @Word@ counterparts.+ , plusDim, minusDim, minusDimM, timesDim, powerDim, divDim, modDim, log2Dim+ -- ** Re-export part of `Data.Type.Lits` for convenience+ , Nat, CmpNat, SOrdering (..), type (+), type (-), type (*), type (^), type (<=)+ -- ** Inferring kind of type-level dimension+ , KnownDimKind (..), DimKind (..)+ -- * @Dims@ -- a list of dimensions+ , Dims, SomeDims (..), Dimensions (..), BoundedDims (..), minDims+ , TypedList ( Dims, XDims, AsXDims, KnownDims+ , U, (:*), Empty, TypeList, Cons, Snoc, Reverse)+ , typeableDims, inferTypeableDims+ , listDims, someDimsVal, totalDim, totalDim'+ , sameDims, sameDims'+ , inSpaceOf, asSpaceOf+ , xDims, xDims'+ , stripPrefixDims, stripSuffixDims+ -- ** Type-level programming+ -- Provide type families to work with lists of dimensions (`[Nat]` or `[XNat]`)+ , AsXDims, AsDims, FixedDims, KnownXNatTypes+ -- ** Re-export type list+ , RepresentableList (..), TypeList, types+ , order, order'+ ) where+++import Data.Bits (countLeadingZeros, finiteBitSize)+import Data.Coerce+import Data.Constraint+import Data.Data hiding (TypeRep, typeRep, typeRepTyCon)+import Data.Kind (Constraint, Type)+import qualified Data.List (stripPrefix)+import Data.Type.List+import Data.Type.Lits+import GHC.Exts (Proxy#, proxy#, unsafeCoerce#)+import qualified GHC.Generics as G+import Numeric.Natural (Natural)+import Numeric.TypedList+import qualified Text.Read as Read+import qualified Text.Read.Lex as Read+import Type.Reflection+++-- | Either known or unknown at compile-time natural number+data XNat = XN Nat | N Nat+-- | Unknown natural number, known to be not smaller than the given Nat+type XN (n::Nat) = 'XN n+-- | Known natural number+type N (n::Nat) = 'N n++-- | Find out whether @XNat@ is of known or constrained type.+data XNatType :: XNat -> Type where+ -- | Given @XNat@ is known+ Nt :: XNatType ('N n)+ -- | Given @XNat@ is constrained unknown+ XNt :: XNatType ('XN m)++-- | Same as `SomeNat`+type SomeDim = Dim ('XN 0)++-- | Singleton type to store type-level dimension value.+--+-- On the one hand, it can be used to let type-inference system know+-- relations between type-level naturals.+-- On the other hand, this is just a newtype wrapper on the @Word@ type.+--+-- Usually, the type parameter of @Dim@ is either @Nat@ or @XNat@.+-- If dimensionality of your data is known in advance, use @Nat@;+-- if you know the size of some dimensions, but do not know the size+-- of others, use @XNat@s to represent them.+newtype Dim (x :: k) = DimSing Word+ deriving ( Typeable )++-- | Type-level dimensionality.+type Dims (xs :: [k]) = TypedList Dim xs++-- | Match against this pattern to bring `KnownDim` instance into scope.+pattern D :: forall (n :: Nat) . () => KnownDim n => Dim n+pattern D <- (dimEv -> Dict)+ where+ D = dim @n+{-# COMPLETE D #-}++-- | Statically known `XNat`+pattern Dn :: forall (xn :: XNat) . KnownXNatType xn+ => forall (n :: Nat) . (KnownDim n, xn ~ 'N n) => Dim n -> Dim xn+pattern Dn k <- (dimXNEv (xNatType @xn) -> PatN k)+ where+ Dn k = coerce k++-- | `XNat` that is unknown at compile time.+-- Same as `SomeNat`, but for a dimension:+-- Hide dimension size inside, but allow specifying its minimum possible value.+pattern Dx :: forall (xn :: XNat) . KnownXNatType xn+ => forall (n :: Nat) (m :: Nat)+ . (KnownDim n, m <= n, xn ~ 'XN m) => Dim n -> Dim xn+pattern Dx k <- (dimXNEv (xNatType @xn) -> PatXN k)+ where+ Dx k = coerce k+{-# COMPLETE Dn, Dx #-}++-- | This class provides the `Dim` associated with a type-level natural.+--+-- Note, kind of the @KnownDim@ argument is always @Nat@, because+-- it is impossible to create a unique @KnownDim (XN m)@ instance.+class KnownDim (n :: Nat) where+ -- | Get value of type-level dim at runtime.+ --+ -- Note, this function is supposed to be used with @TypeApplications@.+ -- For example, you can type:+ --+ -- >>>:set -XTypeApplications+ -- >>>:set -XDataKinds+ -- >>>:t dim @3+ -- dim @3 :: Dim 3+ --+ -- >>>:set -XTypeOperators+ -- >>>:t dim @(13 - 6)+ -- dim @(13 - 6) :: Dim 7+ --+ dim :: Dim n++-- | Get a minimal or exact bound of a @Dim@.+--+-- To satisfy the @BoundedDim@ means to be equal to @N n@ or be not less than @XN m@.+class KnownDimKind k => BoundedDim (n :: k) where+ -- | Minimal or exact bound of a @Dim@.+ -- Useful for indexing: it is safe to index something by an index less than+ -- @DimBound n@ (for both @Nat@ and @Xnat@ indexed dims).+ type family DimBound n :: Nat+ -- | Get such a minimal @Dim (DimBound n)@, that @Dim n@ is guaranteed+ -- to be not less than @dimBound@ if @n ~ XN a@,+ -- otherwise, the return @Dim@ is the same as @n@.+ dimBound :: Dim (DimBound n)+ -- | If the runtime value of @Dim y@ satisfies @dimBound @k @x@,+ -- then coerce to @Dim x@. Otherwise, return @Nothing@.+ --+ -- To satisfy the @dimBound@ means to be equal to @N n@ or be not less than @XN m@.+ constrainDim :: forall (l :: Type) (y :: l) . Dim y -> Maybe (Dim n)+++instance KnownDim n => BoundedDim (n :: Nat) where+ type DimBound n = n+ dimBound = dim @n+ {-# INLINE dimBound #-}+ constrainDim (DimSing y)+ | dimVal' @n == y = Just (DimSing y)+ | otherwise = Nothing+ {-# INLINE constrainDim #-}++instance KnownDim n => BoundedDim ('N n) where+ type DimBound ('N n) = n+ dimBound = dim @n+ {-# INLINE dimBound #-}+ constrainDim (DimSing y)+ | dimVal' @n == y = Just (DimSing y)+ | otherwise = Nothing+ {-# INLINE constrainDim #-}++instance KnownDim m => BoundedDim ('XN m) where+ type DimBound ('XN m) = m+ dimBound = dim @m+ {-# INLINE dimBound #-}+ constrainDim (DimSing y)+ | dimVal' @m <= y = Just (DimSing y)+ | otherwise = Nothing+ {-# INLINE constrainDim #-}++minDim :: forall (k :: Type) (d :: k) . BoundedDim d => Dim d+minDim = coerce (dimBound @k @d)++-- | Find out the type of `XNat` constructor+class KnownXNatType (n :: XNat) where+ -- | Pattern-match against this to out the type of `XNat` constructor+ xNatType :: XNatType n++instance KnownXNatType ('N n) where+ xNatType = Nt+ {-# INLINE xNatType #-}++instance KnownXNatType ('XN n) where+ xNatType = XNt+ {-# INLINE xNatType #-}++-- | Similar to `natVal` from `GHC.TypeNats`, but returns `Word`.+dimVal :: forall (k :: Type) (x :: k) . Dim (x :: k) -> Word+dimVal = coerce+{-# INLINE dimVal #-}++-- | Similar to `natVal` from `GHC.TypeNats`, but returns `Word`.+dimVal' :: forall (n :: Nat) . KnownDim n => Word+dimVal' = coerce (dim @n)+{-# INLINE dimVal' #-}++-- | Construct a @Dim n@ if there is an instance of @Typeable n@ around.+typeableDim :: forall (n :: Nat) . Typeable n => Dim n+{- YES, that's right. TyCon of a Nat is a string containing the Nat value.+ There simply no place in a TyCon to keep the Nat as a number+ (check GHC.Types for the definition of TyCon).++ Here is an excert from Data.Typeable.Internal:++ -- | Used to make `'Typeable' instance for things of kind Nat+ typeNatTypeRep :: KnownNat a => Proxy# a -> TypeRep a+ typeNatTypeRep p = typeLitTypeRep (show (natVal' p)) tcNat++ -}+typeableDim = DimSing . read . tyConName . typeRepTyCon $ typeRep @n+{-# INLINE typeableDim #-}++-- | Constraints given by an XNat type on possible values of a Nat hidden inside.+type family FixedDim (x :: XNat) (n :: Nat) :: Constraint where+ FixedDim ('N a) b = a ~ b+ FixedDim ('XN m) b = m <= b++instance {-# OVERLAPPABLE #-} KnownNat n => KnownDim n where+ {-# INLINE dim #-}+ dim = DimSing (fromIntegral (natVal' (proxy# :: Proxy# n)))++instance {-# OVERLAPPING #-} KnownDim 0 where+ { {-# INLINE dim #-}; dim = DimSing 0 }+instance {-# OVERLAPPING #-} KnownDim 1 where+ { {-# INLINE dim #-}; dim = DimSing 1 }+instance {-# OVERLAPPING #-} KnownDim 2 where+ { {-# INLINE dim #-}; dim = DimSing 2 }+instance {-# OVERLAPPING #-} KnownDim 3 where+ { {-# INLINE dim #-}; dim = DimSing 3 }+instance {-# OVERLAPPING #-} KnownDim 4 where+ { {-# INLINE dim #-}; dim = DimSing 4 }+instance {-# OVERLAPPING #-} KnownDim 5 where+ { {-# INLINE dim #-}; dim = DimSing 5 }+instance {-# OVERLAPPING #-} KnownDim 6 where+ { {-# INLINE dim #-}; dim = DimSing 6 }+instance {-# OVERLAPPING #-} KnownDim 7 where+ { {-# INLINE dim #-}; dim = DimSing 7 }+instance {-# OVERLAPPING #-} KnownDim 8 where+ { {-# INLINE dim #-}; dim = DimSing 8 }+instance {-# OVERLAPPING #-} KnownDim 9 where+ { {-# INLINE dim #-}; dim = DimSing 9 }+instance {-# OVERLAPPING #-} KnownDim 10 where+ { {-# INLINE dim #-}; dim = DimSing 10 }+instance {-# OVERLAPPING #-} KnownDim 11 where+ { {-# INLINE dim #-}; dim = DimSing 11 }+instance {-# OVERLAPPING #-} KnownDim 12 where+ { {-# INLINE dim #-}; dim = DimSing 12 }+instance {-# OVERLAPPING #-} KnownDim 13 where+ { {-# INLINE dim #-}; dim = DimSing 13 }+instance {-# OVERLAPPING #-} KnownDim 14 where+ { {-# INLINE dim #-}; dim = DimSing 14 }+instance {-# OVERLAPPING #-} KnownDim 15 where+ { {-# INLINE dim #-}; dim = DimSing 15 }+instance {-# OVERLAPPING #-} KnownDim 16 where+ { {-# INLINE dim #-}; dim = DimSing 16 }+instance {-# OVERLAPPING #-} KnownDim 17 where+ { {-# INLINE dim #-}; dim = DimSing 17 }+instance {-# OVERLAPPING #-} KnownDim 18 where+ { {-# INLINE dim #-}; dim = DimSing 18 }+instance {-# OVERLAPPING #-} KnownDim 19 where+ { {-# INLINE dim #-}; dim = DimSing 19 }+instance {-# OVERLAPPING #-} KnownDim 20 where+ { {-# INLINE dim #-}; dim = DimSing 20 }+instance {-# OVERLAPPING #-} KnownDim 21 where+ { {-# INLINE dim #-}; dim = DimSing 21 }+instance {-# OVERLAPPING #-} KnownDim 22 where+ { {-# INLINE dim #-}; dim = DimSing 22 }+instance {-# OVERLAPPING #-} KnownDim 23 where+ { {-# INLINE dim #-}; dim = DimSing 23 }+instance {-# OVERLAPPING #-} KnownDim 24 where+ { {-# INLINE dim #-}; dim = DimSing 24 }+instance {-# OVERLAPPING #-} KnownDim 25 where+ { {-# INLINE dim #-}; dim = DimSing 25 }++instance Class (KnownNat n) (KnownDim n) where+ cls = Sub $ reifyNat @_ @n (fromIntegral $ dimVal' @n) Dict++-- | Similar to `someNatVal` from `GHC.TypeNats`.+someDimVal :: Word -> SomeDim+someDimVal = coerce+{-# INLINE someDimVal #-}++-- | `constrainDim` with explicitly-passed constraining @Dim@+-- to avoid @AllowAmbiguousTypes@.+constrainBy :: forall (k :: Type) (x :: k) (p :: k -> Type) (l :: Type) (y :: l)+ . BoundedDim x => p x -> Dim y -> Maybe (Dim x)+constrainBy = const (constrainDim @k @x @l @y)+{-# INLINE constrainBy #-}++-- | Decrease minimum allowed size of a @Dim (XN x)@.+relax :: forall (m :: Nat) (n :: Nat) . (<=) m n => Dim (XN n) -> Dim (XN m)+relax = coerce+{-# INLINE relax #-}++-- | We either get evidence that this function+-- was instantiated with the same type-level numbers, or Nothing.+--+-- Note, this function works on @Nat@-indexed dimensions only,+-- because @Dim (XN x)@ does not have runtime evidence to infer @x@+-- and `KnownDim x` does not imply `KnownDim (XN x)`.+sameDim :: forall (x :: Nat) (y :: Nat)+ . Dim x -> Dim y -> Maybe (Dict (x ~ y))+sameDim (DimSing a) (DimSing b)+ | a == b = Just (unsafeCoerceDict @(x ~ x) Dict)+ | otherwise = Nothing+{-# INLINE sameDim #-}++-- | We either get evidence that this function+-- was instantiated with the same type-level numbers, or Nothing.+sameDim' :: forall (x :: Nat) (y :: Nat) (p :: Nat -> Type) (q :: Nat -> Type)+ . (KnownDim x, KnownDim y)+ => p x -> q y -> Maybe (Dict (x ~ y))+sameDim' = const . const $ sameDim (dim @x) (dim @y)+{-# INLINE sameDim' #-}++-- | Ordering of dimension values.+--+-- Note: `CmpNat` forces type parameters to kind `Nat`;+-- if you want to compare unknown `XNat`s, use `Ord` instance of `Dim`.+compareDim :: forall (a :: Nat) (b :: Nat)+ . Dim a -> Dim b -> SOrdering (CmpNat a b)+compareDim a b+ = case coerce (compare :: Word -> Word -> Ordering) a b of+ LT -> unsafeCoerce# SLT+ EQ -> unsafeCoerce# SEQ+ GT -> unsafeCoerce# SGT+{-# INLINE compareDim #-}++-- | Ordering of dimension values.+--+-- Note: `CmpNat` forces type parameters to kind `Nat`;+-- if you want to compare unknown `XNat`s, use `Ord` instance of `Dim`.+compareDim' :: forall (a :: Nat) (b :: Nat) (p :: Nat -> Type) (q :: Nat -> Type)+ . (KnownDim a, KnownDim b) => p a -> q b -> SOrdering (CmpNat a b)+compareDim' = const . const $ compareDim (dim @a) (dim @b)+{-# INLINE compareDim' #-}++plusDim :: forall (n :: Nat) (m :: Nat) . Dim n -> Dim m -> Dim (n + m)+plusDim = coerce ((+) :: Word -> Word -> Word)+{-# INLINE plusDim #-}++minusDim :: forall (n :: Nat) (m :: Nat) . (<=) m n => Dim n -> Dim m -> Dim (n - m)+minusDim = coerce ((-) :: Word -> Word -> Word)+{-# INLINE minusDim #-}++minusDimM :: forall (n :: Nat) (m :: Nat) . Dim n -> Dim m -> Maybe (Dim (n - m))+minusDimM (DimSing a) (DimSing b)+ | a >= b = Just (coerce (a - b))+ | otherwise = Nothing+{-# INLINE minusDimM #-}++timesDim :: forall (n :: Nat) (m :: Nat) . Dim n -> Dim m -> Dim ((*) n m)+timesDim = coerce ((*) :: Word -> Word -> Word)+{-# INLINE timesDim #-}++powerDim :: forall (n :: Nat) (m :: Nat) . Dim n -> Dim m -> Dim ((^) n m)+powerDim = coerce ((^) :: Word -> Word -> Word)+{-# INLINE powerDim #-}++divDim :: forall (n :: Nat) (m :: Nat) . Dim n -> Dim m -> Dim (Div n m)+divDim = coerce (div :: Word -> Word -> Word)++modDim :: forall (n :: Nat) (m :: Nat) . Dim n -> Dim m -> Dim (Mod n m)+modDim = coerce (mod :: Word -> Word -> Word)++log2Dim :: forall (n :: Nat) . Dim n -> Dim (Log2 n)+log2Dim (DimSing 0) = undefined+log2Dim (DimSing x) = DimSing . fromIntegral $ finiteBitSize x - 1 - countLeadingZeros x+++-- | GADT to support `KnownDimKind` type class.+-- Match against its constructors to know if @k@ is @Nat@ or @XNat@+data DimKind :: Type -> Type where+ -- | Working on @Nat@.+ DimNat :: DimKind Nat+ -- | Working on @XNat@.+ DimXNat :: DimKind XNat++-- | Figure out whether the type-level dimension is `Nat` or `XNat`.+-- Useful for generalized inference functions.+class KnownDimKind (k :: Type) where+ dimKind :: DimKind k++instance KnownDimKind Nat where+ dimKind = DimNat++instance KnownDimKind XNat where+ dimKind = DimXNat+++-- | Match @Dim n@ against a concrete @Nat@+pattern D0 :: forall (n :: Nat) . () => n ~ 0 => Dim n+pattern D0 <- (sameDim (D @0) -> Just Dict)+ where D0 = DimSing 0++-- | Match @Dim n@ against a concrete @Nat@+pattern D1 :: forall (n :: Nat) . () => n ~ 1 => Dim n+pattern D1 <- (sameDim (D @1) -> Just Dict)+ where D1 = DimSing 1++-- | Match @Dim n@ against a concrete @Nat@+pattern D2 :: forall (n :: Nat) . () => n ~ 2 => Dim n+pattern D2 <- (sameDim (D @2) -> Just Dict)+ where D2 = DimSing 2++-- | Match @Dim n@ against a concrete @Nat@+pattern D3 :: forall (n :: Nat) . () => n ~ 3 => Dim n+pattern D3 <- (sameDim (D @3) -> Just Dict)+ where D3 = DimSing 3++-- | Match @Dim n@ against a concrete @Nat@+pattern D4 :: forall (n :: Nat) . () => n ~ 4 => Dim n+pattern D4 <- (sameDim (D @4) -> Just Dict)+ where D4 = DimSing 4++-- | Match @Dim n@ against a concrete @Nat@+pattern D5 :: forall (n :: Nat) . () => n ~ 5 => Dim n+pattern D5 <- (sameDim (D @5) -> Just Dict)+ where D5 = DimSing 5++-- | Match @Dim n@ against a concrete @Nat@+pattern D6 :: forall (n :: Nat) . () => n ~ 6 => Dim n+pattern D6 <- (sameDim (D @6) -> Just Dict)+ where D6 = DimSing 6++-- | Match @Dim n@ against a concrete @Nat@+pattern D7 :: forall (n :: Nat) . () => n ~ 7 => Dim n+pattern D7 <- (sameDim (D @7) -> Just Dict)+ where D7 = DimSing 7++-- | Match @Dim n@ against a concrete @Nat@+pattern D8 :: forall (n :: Nat) . () => n ~ 8 => Dim n+pattern D8 <- (sameDim (D @8) -> Just Dict)+ where D8 = DimSing 8++-- | Match @Dim n@ against a concrete @Nat@+pattern D9 :: forall (n :: Nat) . () => n ~ 9 => Dim n+pattern D9 <- (sameDim (D @9) -> Just Dict)+ where D9 = DimSing 9++-- | Match @Dim n@ against a concrete @Nat@+pattern D10 :: forall (n :: Nat) . () => n ~ 10 => Dim n+pattern D10 <- (sameDim (D @10) -> Just Dict)+ where D10 = DimSing 10++-- | Match @Dim n@ against a concrete @Nat@+pattern D11 :: forall (n :: Nat) . () => n ~ 11 => Dim n+pattern D11 <- (sameDim (D @11) -> Just Dict)+ where D11 = DimSing 11++-- | Match @Dim n@ against a concrete @Nat@+pattern D12 :: forall (n :: Nat) . () => n ~ 12 => Dim n+pattern D12 <- (sameDim (D @12) -> Just Dict)+ where D12 = DimSing 12++-- | Match @Dim n@ against a concrete @Nat@+pattern D13 :: forall (n :: Nat) . () => n ~ 13 => Dim n+pattern D13 <- (sameDim (D @13) -> Just Dict)+ where D13 = DimSing 13++-- | Match @Dim n@ against a concrete @Nat@+pattern D14 :: forall (n :: Nat) . () => n ~ 14 => Dim n+pattern D14 <- (sameDim (D @14) -> Just Dict)+ where D14 = DimSing 14++-- | Match @Dim n@ against a concrete @Nat@+pattern D15 :: forall (n :: Nat) . () => n ~ 15 => Dim n+pattern D15 <- (sameDim (D @15) -> Just Dict)+ where D15 = DimSing 15++-- | Match @Dim n@ against a concrete @Nat@+pattern D16 :: forall (n :: Nat) . () => n ~ 16 => Dim n+pattern D16 <- (sameDim (D @16) -> Just Dict)+ where D16 = DimSing 16++-- | Match @Dim n@ against a concrete @Nat@+pattern D17 :: forall (n :: Nat) . () => n ~ 17 => Dim n+pattern D17 <- (sameDim (D @17) -> Just Dict)+ where D17 = DimSing 17++-- | Match @Dim n@ against a concrete @Nat@+pattern D18 :: forall (n :: Nat) . () => n ~ 18 => Dim n+pattern D18 <- (sameDim (D @18) -> Just Dict)+ where D18 = DimSing 18++-- | Match @Dim n@ against a concrete @Nat@+pattern D19 :: forall (n :: Nat) . () => n ~ 19 => Dim n+pattern D19 <- (sameDim (D @19) -> Just Dict)+ where D19 = DimSing 19++-- | Match @Dim n@ against a concrete @Nat@+pattern D20 :: forall (n :: Nat) . () => n ~ 20 => Dim n+pattern D20 <- (sameDim (D @20) -> Just Dict)+ where D20 = DimSing 20++-- | Match @Dim n@ against a concrete @Nat@+pattern D21 :: forall (n :: Nat) . () => n ~ 21 => Dim n+pattern D21 <- (sameDim (D @21) -> Just Dict)+ where D21 = DimSing 21++-- | Match @Dim n@ against a concrete @Nat@+pattern D22 :: forall (n :: Nat) . () => n ~ 22 => Dim n+pattern D22 <- (sameDim (D @22) -> Just Dict)+ where D22 = DimSing 22++-- | Match @Dim n@ against a concrete @Nat@+pattern D23 :: forall (n :: Nat) . () => n ~ 23 => Dim n+pattern D23 <- (sameDim (D @23) -> Just Dict)+ where D23 = DimSing 23++-- | Match @Dim n@ against a concrete @Nat@+pattern D24 :: forall (n :: Nat) . () => n ~ 24 => Dim n+pattern D24 <- (sameDim (D @24) -> Just Dict)+ where D24 = DimSing 24++-- | Match @Dim n@ against a concrete @Nat@+pattern D25 :: forall (n :: Nat) . () => n ~ 25 => Dim n+pattern D25 <- (sameDim (D @25) -> Just Dict)+ where D25 = DimSing 25++++-- | @O(1)@ Pattern-matching against this constructor brings a `Dimensions`+-- instance into the scope.+-- Thus, you can do arbitrary operations on your dims and use this pattern+-- at any time to reconstruct the class instance at runtime.+pattern Dims :: forall (ds :: [Nat]) . () => Dimensions ds => Dims ds+pattern Dims <- (dimsEv -> Dict)+ where+ Dims = dims @ds+{-# COMPLETE Dims #-}++-- | @O(Length ds)@ A heavy weapon against all sorts of type errors+pattern KnownDims :: forall (ds :: [Nat]) . ()+ => ( All KnownDim ds, All BoundedDim ds+ , RepresentableList ds, Dimensions ds)+ => Dims ds+pattern KnownDims <- (patKDims -> PatKDims)+ where+ KnownDims = dims @ds+{-# COMPLETE KnownDims #-}++-- | Pattern-matching against this constructor reveals Nat-kinded list of dims,+-- pretending the dimensionality is known at compile time within the scope+-- of the pattern match.+-- This is the main recommended way to get `Dims` at runtime;+-- for example, reading a list of dimensions from a file.+--+-- In order to use this pattern, one must know @XNat@ type constructors in+-- each dimension at compile time.+pattern XDims :: forall (xns :: [XNat]) . KnownXNatTypes xns+ => forall (ns :: [Nat]) . (FixedDims xns ns, Dimensions ns)+ => Dims ns -> Dims xns+pattern XDims ns <- (patXDims -> PatXDims ns)+ where+ XDims ns = unsafeCoerce# ns+{-# COMPLETE XDims #-}++-- | An easy way to convert Nat-indexed dims into XNat-indexed dims.+pattern AsXDims :: forall (ns :: [Nat]) . ()+ => (KnownXNatTypes (AsXDims ns), RepresentableList (AsXDims ns))+ => Dims (AsXDims ns) -> Dims ns+pattern AsXDims xns <- (patAsXDims -> PatAsXDims xns)+ where+ AsXDims xns = unsafeCoerce# xns+{-# COMPLETE AsXDims #-}++-- | Same as SomeNat, but for Dimensions:+-- Hide all information about Dimensions inside+data SomeDims = forall (ns :: [Nat]) . SomeDims (Dims ns)++-- | Put runtime evidence of `Dims` value inside function constraints.+-- Similar to `KnownDim` or `KnownNat`, but for lists of numbers.+--+-- Note, kind of the @Dimensions@ list is always @Nat@, restricted by+-- @KnownDim@ being also @Nat@-indexed+-- (it is impossible to create a unique @KnownDim (XN m)@ instance).+class Dimensions (ds :: [Nat]) where+ -- | Get dimensionality of a space at runtime,+ -- represented as a list of `Dim`.+ --+ -- Note, this function is supposed to be used with @TypeApplications@.+ -- For example, you can type:+ --+ -- >>>:set -XTypeApplications+ -- >>>:set -XDataKinds+ -- >>>:t dims @'[17, 12]+ -- dims @'[17, 12] :: Dims '[17, 12]+ --+ -- >>>:t dims @'[]+ -- dims @'[] :: Dims '[]+ --+ -- >>>:t dims @(Tail '[3,2,5,7])+ -- dims @(Tail '[3,2,5,7]) :: Dims '[2, 5, 7]+ --+ dims :: Dims ds++instance Dimensions '[] where+ dims = U+ {-# INLINE dims #-}++instance (KnownDim d, Dimensions ds) => Dimensions (d ': ds) where+ dims = dim :* dims+ {-# INLINE dims #-}+++-- | Get a minimal or exact bound of @Dims@.+--+-- This is a plural form of `BoundedDim`.+--+-- @BoundedDims@ is a somewhat weaker form of @Dimensions@:+--+-- * It is defined for both @[Nat]@ and @[XNat]@;+-- * Instance of @Dimensions ds@ always implies @BoundedDims ds@.+class KnownDimKind k => BoundedDims (ds :: [k]) where+ -- | Minimal or exact bound of @Dims@.+ -- This is a plural form of `DimBound`.+ type family DimsBound ds :: [Nat]+ -- | Plural form for `dimBound`+ dimsBound :: Dims (DimsBound ds)+ -- | Plural form for `constrainDim`.+ --+ -- Given a @Dims ys@, test if its runtime value satisfies constraints imposed by+ -- @BoundedDims ds@, and returns it back coerced to @Dims ds@ on success.+ --+ -- This function allows to guess safely individual dimension values,+ -- as well as the length of the dimension list.+ -- It returns @Nothing@ if @ds@ and @xds@ have different length or if any+ -- of the values in @ys@ are less than the corresponding values of @ds@.+ constrainDims :: forall (l :: Type) (ys :: [l]) . Dims ys -> Maybe (Dims ds)+ -- | BoundedDims means every element dim is @BoundedDim@ and also+ -- the length of a dim list is known.+ --+ -- Enforcing this as a superclass would complicate instance relations,+ -- so it is better to provide these dictionaries on-demand.+ inferAllBoundedDims :: Dict (All BoundedDim ds, RepresentableList ds)+++instance Dimensions ns => BoundedDims (ns :: [Nat]) where+ type DimsBound ns = ns+ dimsBound = dims @ns+ {-# INLINE dimsBound #-}+ constrainDims ys+ | listDims ys == listDims (dims @ns)+ = Just (unsafeCoerce# ys)+ | otherwise = Nothing+ {-# INLINE constrainDims #-}+ inferAllBoundedDims = go (dims @ns)+ where+ go :: forall (ds :: [Nat]) . Dims ds+ -> Dict (All BoundedDim ds, RepresentableList ds)+ go U = Dict+ go (D :* ds)+ | Dict <- go ds = Dict++instance BoundedDims ('[] :: [XNat]) where+ type DimsBound '[] = '[]+ dimsBound = U+ constrainDims = const $ Just U+ inferAllBoundedDims = Dict++instance (BoundedDim n, BoundedDims ns) => BoundedDims ((n ': ns) :: [XNat]) where+ type DimsBound (n ': ns) = DimBound n ': DimsBound ns+ dimsBound = dimBound @XNat @n :* dimsBound @XNat @ns+ constrainDims U = Nothing+ constrainDims (y :* ys) = (:*) <$> constrainDim y <*> constrainDims ys+ inferAllBoundedDims = case inferAllBoundedDims @XNat @ns of Dict -> Dict+++-- | Minimal runtime @Dims ds@ value that satifies the constraints imposed by+-- the type signature of @Dims ds@.+minDims :: forall (k :: Type) (ds :: [k])+ . BoundedDims ds => Dims ds+minDims = unsafeCoerce# (dimsBound @k @ds)+++++-- | Construct a @Dims ds@ if there is an instance of @Typeable ds@ around.+typeableDims :: forall (ds :: [Nat]) . Typeable ds => Dims ds+typeableDims = case typeRep @ds of+ App (App _ (tx :: TypeRep (n :: k1))) (txs :: TypeRep (ns :: k2))+ -> case unsafeCoerceDict @(Nat ~ Nat, [Nat] ~ [Nat])+ @(Nat ~ k1 , [Nat] ~ k2) Dict of+ Dict -> case unsafeCoerceDict @(ds ~ ds)+ @(ds ~ (n ': ns)) Dict of+ Dict -> withTypeable tx (typeableDim @n)+ :* withTypeable txs (typeableDims @ns)+ Con _+ -> unsafeCoerce# U+ r -> error ("typeableDims -- impossible typeRep: " ++ show r)+{-# INLINE typeableDims #-}++-- | @Dims (ds :: [Nat])@ is always @Typeable@.+inferTypeableDims :: forall (ds :: [Nat]) . Dims ds -> Dict (Typeable ds)+inferTypeableDims U = Dict+inferTypeableDims ((D :: Dim d) :* ds)+ | Dict <- mapDict cls (Dict @(KnownDim d))+ , Dict <- inferTypeableDims ds+ = Dict+++-- | Convert `Dims xs` to a plain haskell list of dimension sizes @O(1)@.+--+-- Note, for @XNat@-indexed list it returns actual content dimensions,+-- not the constraint numbers (@XN m@)+listDims :: forall (k :: Type) (xs :: [k]) . Dims xs -> [Word]+listDims = unsafeCoerce#+{-# INLINE listDims #-}++-- | Convert a plain haskell list of dimension sizes into an unknown+-- type-level dimensionality @O(1)@.+someDimsVal :: [Word] -> SomeDims+someDimsVal = SomeDims . unsafeCoerce#+{-# INLINE someDimsVal #-}++-- | Product of all dimension sizes @O(Length xs)@.+totalDim :: forall (k :: Type) (xs :: [k]) . Dims xs -> Word+totalDim = product . listDims+{-# INLINE totalDim #-}++-- | Product of all dimension sizes @O(Length xs)@.+totalDim' :: forall (xs :: [Nat]) . Dimensions xs => Word+totalDim' = totalDim (dims @xs)+{-# INLINE totalDim' #-}++-- | Get XNat-indexed dims given their fixed counterpart.+xDims :: forall (xns :: [XNat]) (ns :: [Nat])+ . FixedDims xns ns => Dims ns -> Dims xns+xDims = unsafeCoerce#+{-# INLINE xDims #-}++-- | Get XNat-indexed dims given their fixed counterpart.+xDims' :: forall (xns :: [XNat]) (ns :: [Nat])+ . (FixedDims xns ns, Dimensions ns) => Dims xns+xDims' = xDims @xns (dims @ns)+{-# INLINE xDims' #-}++-- | Drop the given prefix from a Dims list.+-- It returns Nothing if the list did not start with the prefix given,+-- or Just the Dims after the prefix, if it does.+stripPrefixDims :: forall (xs :: [Nat]) (ys :: [Nat])+ . Dims xs -> Dims ys+ -> Maybe (Dims (StripPrefix xs ys))+stripPrefixDims = unsafeCoerce# (Data.List.stripPrefix :: [Word] -> [Word] -> Maybe [Word])+{-# INLINE stripPrefixDims #-}++-- | Drop the given suffix from a Dims list.+-- It returns Nothing if the list did not end with the suffix given,+-- or Just the Dims before the suffix, if it does.+stripSuffixDims :: forall (xs :: [Nat]) (ys :: [Nat])+ . Dims xs -> Dims ys+ -> Maybe (Dims (StripSuffix xs ys))+stripSuffixDims = unsafeCoerce# stripSuf+ where+ stripSuf :: [Word] -> [Word] -> Maybe [Word]+ stripSuf suf whole = go pref whole+ where+ pref = getPref suf whole+ getPref (_:as) (_:bs) = getPref as bs+ getPref [] bs = zipWith const whole bs+ getPref _ [] = []+ go (_:as) (_:bs) = go as bs+ go [] bs = if suf == bs then Just pref else Nothing+ go _ [] = Nothing+{-# INLINE stripSuffixDims #-}++-- | We either get evidence that this function was instantiated with the+-- same type-level Dimensions, or 'Nothing' @O(Length xs)@.+sameDims :: forall (as :: [Nat]) (bs :: [Nat])+ . Dims as -> Dims bs -> Maybe (Dict (as ~ bs))+sameDims as bs+ | listDims as == listDims bs+ = Just (unsafeCoerceDict @(as ~ as) Dict)+ | otherwise = Nothing+{-# INLINE sameDims #-}++-- | We either get evidence that this function was instantiated with the+-- same type-level Dimensions, or 'Nothing' @O(Length xs)@.+sameDims' :: forall (as :: [Nat]) (bs :: [Nat]) (p :: [Nat] -> Type) (q :: [Nat] -> Type)+ . (Dimensions as, Dimensions bs)+ => p as -> q bs -> Maybe (Dict (as ~ bs))+sameDims' = const . const $ sameDims (dims @as) (dims @bs)+{-# INLINE sameDims' #-}+++-- | Similar to `const` or `asProxyTypeOf`;+-- to be used on such implicit functions as `dim`, `dimMax`, etc.+inSpaceOf :: forall (k :: Type) (ds :: [k]) (p :: [k] -> Type) (q :: [k] -> Type)+ . p ds -> q ds -> p ds+inSpaceOf = const+{-# INLINE inSpaceOf #-}++-- | Similar to `asProxyTypeOf`,+-- Give a hint to type checker to fix the type of a function argument.+asSpaceOf :: forall (k :: Type) (ds :: [k])+ (p :: [k] -> Type) (q :: [k] -> Type) (r :: Type)+ . p ds -> (q ds -> r) -> (q ds -> r)+asSpaceOf = const id+{-# INLINE asSpaceOf #-}++-- | Map Dims onto XDims (injective)+type family AsXDims (ns :: [Nat]) = (xns :: [XNat]) | xns -> ns where+ AsXDims '[] = '[]+ AsXDims (n ': ns) = N n ': AsXDims ns++-- | Map XDims onto Dims (injective)+type family AsDims (xns::[XNat]) = (ns :: [Nat]) | ns -> xns where+ AsDims '[] = '[]+ AsDims (N x ': xs) = x ': AsDims xs++-- | Constrain @Nat@ dimensions hidden behind @XNat@s.+type family FixedDims (xns::[XNat]) (ns :: [Nat]) :: Constraint where+ FixedDims '[] ns = (ns ~ '[])+ FixedDims (xn ': xns) ns+ = ( ns ~ (Head ns ': Tail ns)+ , FixedDim xn (Head ns)+ , FixedDims xns (Tail ns))++-- | Know the structure of each dimension+type KnownXNatTypes xns = All KnownXNatType xns+++++instance Typeable d => Data (Dim (d :: Nat)) where+ gfoldl _ = id+ gunfold _ z = const (z (typeableDim @d))+ toConstr = const $ dimNatConstr (dimVal (typeableDim @d))+ dataTypeOf = const $ dimDataType (dimVal (typeableDim @d))++dimDataType :: Word -> DataType+dimDataType = mkDataType "Numeric.Dim.Dim" . (:[]) . dimNatConstr++dimNatConstr :: Word -> Constr+dimNatConstr d = mkConstr (dimDataType d) ("D" ++ show d) [] Prefix++instance KnownDim d => G.Generic (Dim (d :: Nat)) where+ type Rep (Dim d) = G.D1+ ('G.MetaData "Dim" "Numeric.Dim" "dimensions" 'False)+ (G.C1 ('G.MetaCons (AppendSymbol "D" (ShowNat d)) 'G.PrefixI 'False) G.U1)+ from D = G.M1 (G.M1 G.U1)+ to = const (dim @d)++instance Eq (Dim (n :: Nat)) where+ (==) = const (const True)+ {-# INLINE (==) #-}+ (/=) = const (const False)+ {-# INLINE (/=) #-}++instance Eq (Dim (x :: XNat)) where+ (==) = coerce ((==) :: Word -> Word -> Bool)+ {-# INLINE (==) #-}+ (/=) = coerce ((/=) :: Word -> Word -> Bool)+ {-# INLINE (/=) #-}++instance Eq (Dims (ds :: [Nat])) where+ (==) = const (const True)+ {-# INLINE (==) #-}+ (/=) = const (const False)+ {-# INLINE (/=) #-}++instance Eq (Dims (ds :: [XNat])) where+ (==) = unsafeCoerce# ((==) :: [Word] -> [Word] -> Bool)+ {-# INLINE (==) #-}+ (/=) = unsafeCoerce# ((/=) :: [Word] -> [Word] -> Bool)+ {-# INLINE (/=) #-}++instance Eq SomeDims where+ SomeDims as == SomeDims bs = listDims as == listDims bs+ {-# INLINE (==) #-}+ SomeDims as /= SomeDims bs = listDims as /= listDims bs+ {-# INLINE (/=) #-}++instance Ord (Dim (n :: Nat)) where+ compare = const (const EQ)+ {-# INLINE compare #-}++instance Ord (Dim (x :: XNat)) where+ compare = coerce (compare :: Word -> Word -> Ordering)+ {-# INLINE compare #-}++instance Ord (Dims (ds :: [Nat])) where+ compare = const (const EQ)+ {-# INLINE compare #-}++instance Ord (Dims (ds :: [XNat])) where+ compare = unsafeCoerce# (compare :: [Word] -> [Word] -> Ordering)+ {-# INLINE compare #-}++instance Ord SomeDims where+ compare (SomeDims as) (SomeDims bs) = compare (listDims as) (listDims bs)+ {-# INLINE compare #-}++instance Show (Dim (x :: k)) where+ showsPrec _ d = showChar 'D' . shows (dimVal d)+ {-# INLINE showsPrec #-}++instance Show (Dims (xs :: [k])) where+ showsPrec = typedListShowsPrec @k @Dim @xs showsPrec++instance Show SomeDims where+ showsPrec p (SomeDims ds)+ = showParen (p >= 10)+ $ showString "SomeDims " . showsPrec 10 ds++instance BoundedDim x => Read (Dim (x :: k)) where+ readPrec = Read.lexP >>= \case+ Read.Ident ('D':s)+ | Just d <- Read.readMaybe s+ >>= constrainDim @k @x @XNat @(XN 0) . DimSing+ -> return d+ _ -> Read.pfail+ readList = Read.readListDefault+ readListPrec = Read.readListPrecDefault++instance BoundedDims xs => Read (Dims (xs :: [k])) where+ readPrec = case inferAllBoundedDims @k @xs of+ Dict -> typedListReadPrec @k @BoundedDim ":*" Read.readPrec (tList @k @xs)+ readList = Read.readListDefault+ readListPrec = Read.readListPrecDefault++instance Read SomeDims where+ readPrec = Read.parens . Read.prec 10 $ do+ Read.lift . Read.expect $ Read.Ident "SomeDims"+ withTypedListReadPrec @Nat @Dim @SomeDims+ (\g -> (\(Dx d) -> g d) <$> Read.readPrec @(Dim (XN 0)))+ SomeDims++++-- | This function does GHC's magic to convert user-supplied `dim` function+-- to create an instance of `KnownDim` typeclass at runtime.+-- The trick is taken from Edward Kmett's reflection library explained+-- in https://www.schoolofhaskell.com/user/thoughtpolice/using-reflection+reifyDim :: forall (r :: Type) (d :: Nat) . Dim d -> (KnownDim d => r) -> r+reifyDim d k = unsafeCoerce# (MagicDim k :: MagicDim d r) d+{-# INLINE reifyDim #-}+newtype MagicDim (d :: Nat) (r :: Type) = MagicDim (KnownDim d => r)++reifyNat :: forall (r :: Type) (d :: Nat) . Natural -> (KnownNat d => r) -> r+reifyNat d k = unsafeCoerce# (MagicNat k :: MagicNat d r) d+{-# INLINE reifyNat #-}+newtype MagicNat (d :: Nat) (r :: Type) = MagicNat (KnownNat d => r)++dimEv :: forall (d :: Nat) . Dim d -> Dict (KnownDim d)+dimEv d = reifyDim d Dict+{-# INLINE dimEv #-}++reifyDims :: forall (r :: Type) (ds :: [Nat]) . Dims ds -> (Dimensions ds => r) -> r+reifyDims ds k = unsafeCoerce# (MagicDims k :: MagicDims ds r) ds+{-# INLINE reifyDims #-}+newtype MagicDims (ds :: [Nat]) (r :: Type) = MagicDims (Dimensions ds => r)++dimsEv :: forall (ds :: [Nat]) . Dims ds -> Dict (Dimensions ds)+dimsEv ds = reifyDims ds Dict+{-# INLINE dimsEv #-}+++data PatXDim (xn :: XNat) where+ PatN :: KnownDim n => Dim n -> PatXDim ('N n)+ PatXN :: (KnownDim n, m <= n) => Dim n -> PatXDim ('XN m)++dimXNEv :: forall (xn :: XNat) . XNatType xn -> Dim xn -> PatXDim xn+dimXNEv Nt (DimSing k) = reifyDim dd (PatN dd)+ where+ dd = DimSing @Nat @_ k+dimXNEv XNt xn@(DimSing k) = reifyDim dd (f dd xn)+ where+ dd = DimSing @Nat @_ k+ f :: forall (d :: Nat) (m :: Nat)+ . KnownDim d => Dim d -> Dim ('XN m) -> PatXDim ('XN m)+ f d = case unsafeCoerceDict @(m <= m) @(m <= d) Dict of+ Dict -> const (PatXN d)+{-# INLINE dimXNEv #-}++data PatXDims (xns :: [XNat])+ = forall (ns :: [Nat])+ . (FixedDims xns ns, Dimensions ns) => PatXDims (Dims ns)++patXDims :: forall (xns :: [XNat])+ . All KnownXNatType xns => Dims xns -> PatXDims xns+patXDims U = PatXDims U+patXDims (Dn n :* xns) = case patXDims xns of+ PatXDims ns -> PatXDims (n :* ns)+patXDims (Dx n :* xns) = case patXDims xns of+ PatXDims ns -> PatXDims (n :* ns)+{-# INLINE patXDims #-}++data PatAsXDims (ns :: [Nat])+ = (KnownXNatTypes (AsXDims ns), RepresentableList (AsXDims ns))+ => PatAsXDims (Dims (AsXDims ns))++patAsXDims :: forall (ns :: [Nat]) . Dims ns -> PatAsXDims ns+patAsXDims U = PatAsXDims U+patAsXDims (n@D :* ns) = case patAsXDims ns of+ PatAsXDims xns -> PatAsXDims (Dn n :* xns)+{-# INLINE patAsXDims #-}++data PatKDims (ns :: [Nat])+ = (All KnownDim ns, All BoundedDim ns, RepresentableList ns, Dimensions ns) => PatKDims++patKDims :: forall (ns :: [Nat]) . Dims ns -> PatKDims ns+patKDims U = PatKDims+patKDims (D :* ns) = case patKDims ns of+ PatKDims -> PatKDims+{-# INLINE patKDims #-}++unsafeCoerceDict :: forall (a :: Constraint) (b :: Constraint)+ . Dict a -> Dict b+unsafeCoerceDict = unsafeCoerce#
+ src/Numeric/Dimensions/Dim.hs-boot view
@@ -0,0 +1,13 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE ExplicitForAll #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeInType #-}+{-# LANGUAGE TypeOperators #-}+-- This module recursively depends on Numeric.TypedList.+-- I thought hs-boot is better than orphan instances.+module Numeric.Dimensions.Dim ( Dim, Nat, dimVal, minusDimM ) where+import Data.Kind (Type)+import Data.Type.Lits (type (-), Nat)+newtype Dim (x :: k) = DimSing Word+dimVal :: forall (k :: Type) (x :: k) . Dim (x :: k) -> Word+minusDimM :: forall (n :: Nat) (m :: Nat) . Dim n -> Dim m -> Maybe (Dim (n - m))
− src/Numeric/Dimensions/Dims.hs
@@ -1,440 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE ExplicitNamespaces #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE MagicHash #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE RoleAnnotations #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeFamilyDependencies #-}-{-# LANGUAGE TypeInType #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE UndecidableSuperClasses #-}-{-# LANGUAGE ViewPatterns #-}--------------------------------------------------------------------------------- |--- Module : Numeric.Dimensions.Dims--- Copyright : (c) Artem Chirkin--- License : BSD3------ Maintainer : chirkin@arch.ethz.ch------ Provides a data type `Dims ds` to keep dimension sizes--- for multiple-dimensional data.--- Lower indices go first, i.e. assumed enumeration--- is i = i1 + i2*n1 + i3*n1*n2 + ... + ik*n1*n2*...*n(k-1).-----------------------------------------------------------------------------------module Numeric.Dimensions.Dims- ( Dims, SomeDims (..), Dimensions (..), XDimensions (..)- , TypedList ( Dims, XDims, AsXDims, KnownDims- , U, (:*), Empty, TypeList, Cons, Snoc, Reverse)- , listDims, someDimsVal, totalDim, totalDim'- , sameDims, sameDims'- , compareDims, compareDims'- , inSpaceOf, asSpaceOf- , xDims, xDims'- -- * Type-level programming- -- Provide type families to work with lists of dimensions (`[Nat]` or `[XNat]`)- , AsXDims, AsDims, FixedDims, KnownXNatTypes, type (:<), type (>:)- -- * Re-export type list- , RepresentableList (..), TypeList, types- , order, order'- -- * Re-export single dimension type and functions- , module Numeric.Dim- ) where----import GHC.Exts (unsafeCoerce#, Constraint)-import qualified Text.Read as Read--import Numeric.Dim-import Numeric.Type.Evidence-import Numeric.Type.List-import Numeric.TypedList (RepresentableList (..), TypeList,- TypedList (..), order, order', types)----- | Type-level dimensionality O(1).-type Dims (xs :: [k]) = TypedList Dim xs---- Starting from GHC 8.2, compiler supports specifying lists of complete--- pattern synonyms.-#if __GLASGOW_HASKELL__ >= 802-{-# COMPLETE Dims #-}-{-# COMPLETE XDims #-}-{-# COMPLETE AsXDims #-}-{-# COMPLETE KnownDims #-}-#endif---- | @O(1)@ Pattern-matching against this constructor brings a `Dimensions`--- instance into the scope.--- Thus, you can do arbitrary operations on your dims and use this pattern--- at any time to reconstruct the class instance at runtime.-pattern Dims :: forall ds . () => Dimensions ds => Dims ds-pattern Dims <- (dimsEv -> E)- where- Dims = dims @_ @ds---- | @O(Length ds)@ `Dimensions` and `KnownDim` for each individual dimension.-pattern KnownDims :: forall ds . ()- => (All KnownDim ds, Dimensions ds) => Dims ds-pattern KnownDims <- (patKDims -> PatKDims)- where- KnownDims = dims @_ @ds----- | Pattern-matching against this constructor reveals Nat-kinded list of dims,--- pretending the dimensionality is known at compile time within the scope--- of the pattern match.--- This is the main recommended way to get `Dims` at runtime;--- for example, reading a list of dimensions from a file.------ In order to use this pattern, one must know @XNat@ type constructors in--- each dimension at compile time.-pattern XDims :: forall (xns :: [XNat]) . KnownXNatTypes xns- => forall (ns :: [Nat]) . (FixedDims xns ns, Dimensions ns)- => Dims ns -> Dims xns-pattern XDims ns <- (patXDims -> PatXDims ns)- where- XDims ns = unsafeCoerce# ns---- | An easy way to convert Nat-indexed dims into XNat-indexed dims.-pattern AsXDims :: forall (ns :: [Nat]) . ()- => (KnownXNatTypes (AsXDims ns), RepresentableList (AsXDims ns))- => Dims (AsXDims ns) -> Dims ns-pattern AsXDims xns <- (patAsXDims -> PatAsXDims xns)- where- AsXDims xns = unsafeCoerce# xns---- | Same as SomeNat, but for Dimensions:--- Hide all information about Dimensions inside-data SomeDims = forall (ns :: [Nat]) . SomeDims (Dims ns)---- | Put runtime evidence of `Dims` value inside function constraints.--- Similar to `KnownDim` or `KnownNat`, but for lists of numbers.--- Normally, the kind paramater is `Nat` (known dimenionality)--- or `XNat` (either known or constrained dimensionality).-class Dimensions (ds :: [k]) where- -- | Get dimensionality of a space at runtime,- -- represented as a list of `Dim`.- --- -- Note, this function is supposed to be used with @TypeApplications@,- -- and the @Dimensions@ class has varying kind of the parameter;- -- thus, the function has two type paremeters (kind and type of @ds@).- -- For example, you can type:- --- -- >>>:set -XTypeApplications- -- >>>:set -XDataKinds- -- >>>:t dims @_ @'[N 17, N 12]- -- dims @_ @'[N 17, N 12] :: Dims '[N 17, N 12]- --- -- >>>:t dims @XNat @'[]- -- dims @XNat @'[] :: Dims '[]- --- --- -- >>>:t dims @_ @(Tail '[3,2,5,7])- -- dims @_ @(Tail '[3,2,5,7]) :: Dims '[2, 5, 7]- --- dims :: Dims ds--instance Dimensions ('[] :: [k]) where- dims = U- {-# INLINE dims #-}--instance (KnownDim d, Dimensions ds) => Dimensions (d ': ds :: [k]) where- dims = dim :* dims- {-# INLINE dims #-}---- | Analogous to `Dimensions`, but weaker and more specific (list of `XNat`).--- This class is used to check if an existing fixed `Dims` satisfy--- constraints imposed by some interface (e.g. all dimensions are greater than 2).--- It is weaker than `Dimensions` in that it only requires knowledge of constraints--- rather than exact dimension values.-class KnownXNatTypes xds => XDimensions (xds :: [XNat]) where- -- | Given a `Dims`, test if its runtime value satisfies constraints imposed by- -- @XDimensions@, and returns it back being `XNat`-indexed on success.- --- -- This function allows to guess safely individual dimension values,- -- as well as the length of the dimension list.- constrainDims :: Dims (ds :: [k]) -> Maybe (Dims xds)--instance XDimensions '[] where- constrainDims U = Just U- constrainDims _ = Nothing- {-# INLINE constrainDims #-}--instance (XDimensions xs, KnownDim m) => XDimensions (XN m ': xs) where- constrainDims (d :* ds) = case constrain d of- Nothing -> Nothing- Just xd -> (xd :*) <$> constrainDims ds- constrainDims Empty = Nothing--instance (XDimensions xs, KnownDim n) => XDimensions (N n ': xs) where- constrainDims (d :* ds)- | unsafeCoerce# d == dimVal' @n = (Dn D :*) <$> constrainDims ds- | otherwise = Nothing- constrainDims Empty = Nothing----- | Convert `Dims xs` to a plain haskell list of dimension sizes @O(1)@.-listDims :: Dims xs -> [Word]-listDims = unsafeCoerce#-{-# INLINE listDims #-}---- | Convert a plain haskell list of dimension sizes into an unknown--- type-level dimensionality @O(1)@.-someDimsVal :: [Word] -> SomeDims-someDimsVal = SomeDims . unsafeCoerce#-{-# INLINE someDimsVal #-}---- | Product of all dimension sizes @O(Length xs)@.-totalDim :: Dims xs -> Word-totalDim = product . listDims-{-# INLINE totalDim #-}---- | Product of all dimension sizes @O(Length xs)@.-totalDim' :: forall xs . Dimensions xs => Word-totalDim' = totalDim (dims @_ @xs)-{-# INLINE totalDim' #-}---- | Get XNat-indexed dims given their fixed counterpart.-xDims :: FixedDims xns ns => Dims ns -> Dims xns-xDims = unsafeCoerce#-{-# INLINE xDims #-}---- | Get XNat-indexed dims given their fixed counterpart.-xDims' :: forall xns ns . (FixedDims xns ns, Dimensions ns) => Dims xns-xDims' = xDims @xns (dims @Nat @ns)-{-# INLINE xDims' #-}----- | We either get evidence that this function was instantiated with the--- same type-level Dimensions, or 'Nothing' @O(Length xs)@.------ Note, this function works on @Nat@-indexed dimensions only,--- because @Dims '[XN x]@ does not have runtime evidence to infer @x@--- and `KnownDim x` does not imply `KnownDim (XN x)`.-sameDims :: Dims (as :: [Nat]) -> Dims (bs :: [Nat]) -> Maybe (Evidence (as ~ bs))-sameDims as bs- | listDims as == listDims bs- = Just (unsafeCoerce# (E @('[] ~ '[])))- | otherwise = Nothing-{-# INLINE sameDims #-}----- | We either get evidence that this function was instantiated with the--- same type-level Dimensions, or 'Nothing' @O(Length xs)@.-sameDims' :: forall (as :: [Nat]) (bs :: [Nat]) p q- . (Dimensions as, Dimensions bs)- => p as -> q bs -> Maybe (Evidence (as ~ bs))-sameDims' _ _ = sameDims (dims @Nat @as) (dims @Nat @bs)-{-# INLINE sameDims' #-}---- | Compare dimensions by their size in lexicorgaphic order--- from the last dimension to the first dimension--- (the last dimension is the most significant one).------ Literally,------ > compareDims a b = compare (reverse $ listDims a) (reverse $ listDims b)-compareDims :: Dims as -> Dims bs -> Ordering-compareDims a b = compare (reverse $ listDims a) (reverse $ listDims b)-{-# INLINE compareDims #-}---- | Compare dimensions by their size in lexicorgaphic order--- from the last dimension to the first dimension--- (the last dimension is the most significant one) @O(Length xs)@.------ Literally,------ > compareDims a b = compare (reverse $ listDims a) (reverse $ listDims b)------ This is the same @compare@ rule, as for `Idxs`.-compareDims' :: forall as bs p q- . (Dimensions as, Dimensions bs)- => p as -> q bs -> Ordering-compareDims' _ _ = compareDims (dims @_ @as) (dims @_ @bs)-{-# INLINE compareDims' #-}----- | Similar to `const` or `asProxyTypeOf`;--- to be used on such implicit functions as `dim`, `dimMax`, etc.-inSpaceOf :: a ds -> b ds -> a ds-inSpaceOf x _ = x-{-# INLINE inSpaceOf #-}---- | Similar to `asProxyTypeOf`,--- Give a hint to type checker to fix the type of a function argument.-asSpaceOf :: a ds -> (b ds -> c) -> (b ds -> c)-asSpaceOf _ = id-{-# INLINE asSpaceOf #-}---instance Eq (Dims (ds :: [Nat])) where- (==) _ _ = True--instance Eq (Dims (ds :: [XNat])) where- (==) = unsafeCoerce# ((==) :: [Word] -> [Word] -> Bool)--instance Eq SomeDims where- SomeDims as == SomeDims bs = listDims as == listDims bs--instance Ord (Dims (ds :: [Nat])) where- compare _ _ = EQ--instance Ord (Dims (ds :: [XNat])) where- compare = compareDims--instance Ord SomeDims where- compare (SomeDims as) (SomeDims bs) = compareDims as bs--instance Show (Dims xs) where- show ds = "Dims " ++ show (listDims ds)- showsPrec p ds- = showParen (p >= 10)- $ showString "Dims " . showsPrec p (listDims ds)--instance Show SomeDims where- show (SomeDims ds) = "SomeDims " ++ show (listDims ds)- showsPrec p (SomeDims ds)- = showParen (p >= 10)- $ showString "SomeDims " . showsPrec p (listDims ds)--instance Read SomeDims where- readPrec = Read.parens $ Read.prec 10 $ do- s <- Read.lexP- if s == Read.Ident "SomeDims"- then someDimsVal <$> Read.readPrec- else Read.pfail--instance Dimensions ds => Bounded (Dims ds) where- maxBound = dims- {-# INLINE maxBound #-}- minBound = dims- {-# INLINE minBound #-}------ | Map Dims onto XDims (injective)-type family AsXDims (ns :: [Nat]) = (xns :: [XNat]) | xns -> ns where- AsXDims '[] = '[]- AsXDims (n ': ns) = N n ': AsXDims ns---- | Map XDims onto Dims (injective)-type family AsDims (xns::[XNat]) = (ns :: [Nat]) | ns -> xns where- AsDims '[] = '[]- AsDims (N x ': xs) = x ': AsDims xs---- | Constrain @Nat@ dimensions hidden behind @XNat@s.-type family FixedDims (xns::[XNat]) (ns :: [Nat]) :: Constraint where- FixedDims '[] ns = (ns ~ '[])- FixedDims (xn ': xns) ns- = ( ns ~ (Head ns ': Tail ns)- , FixedDim xn (Head ns)- , FixedDims xns (Tail ns))---- | Know the structure of each dimension-type KnownXNatTypes xns = All KnownXNatType xns----- | Synonym for (:+) that treats Nat values 0 and 1 in a special way:--- it preserves the property that all dimensions are greater than 1.-type family (n :: Nat) :< (ns :: [Nat]) :: [Nat] where- 0 :< _ = '[]- 1 :< ns = ns- n :< ns = n :+ ns-infixr 6 :<---- | Synonym for (+:) that treats Nat values 0 and 1 in a special way:--- it preserves the property that all dimensions are greater than 1.-type family (ns :: [Nat]) >: (n :: Nat) :: [Nat] where- _ >: 0 = '[]- ns >: 1 = ns- ns >: n = ns +: n-infixl 6 >:------------------------------------------------------------------------------------------- | This function does GHC's magic to convert user-supplied `dims` function--- to create an instance of `Dimensions` typeclass at runtime.--- The trick is taken from Edward Kmett's reflection library explained--- in https://www.schoolofhaskell.com/user/thoughtpolice/using-reflection-reifyDims :: forall r ds . Dims ds -> ( Dimensions ds => r) -> r-reifyDims ds k = unsafeCoerce# (MagicDims k :: MagicDims ds r) ds-{-# INLINE reifyDims #-}-newtype MagicDims ds r = MagicDims (Dimensions ds => r)--dimsEv :: Dims ds -> Evidence (Dimensions ds)-dimsEv ds = reifyDims ds E-{-# INLINE dimsEv #-}---data PatXDims (xns :: [XNat])- = forall (ns :: [Nat])- . (FixedDims xns ns, Dimensions ns) => PatXDims (Dims ns)---patXDims :: All KnownXNatType xns => Dims xns -> PatXDims xns-patXDims U = PatXDims U-patXDims (Dn n :* xns) = case patXDims xns of- PatXDims ns -> PatXDims (n :* ns)-patXDims (Dx n :* xns) = case patXDims xns of- PatXDims ns -> PatXDims (n :* ns)-#if __GLASGOW_HASKELL__ >= 802-#else-patXDims _ = error "XDims/patXDims: impossible argument"-#endif-{-# INLINE patXDims #-}---data PatAsXDims (ns :: [Nat])- = (KnownXNatTypes (AsXDims ns), RepresentableList (AsXDims ns))- => PatAsXDims (Dims (AsXDims ns))---patAsXDims :: Dims ns -> PatAsXDims ns-patAsXDims U = PatAsXDims U-patAsXDims (n@D :* ns) = case patAsXDims ns of- PatAsXDims xns -> PatAsXDims (Dn n :* xns)-#if __GLASGOW_HASKELL__ >= 802-#else-patAsXDims _ = error "AsXDims/patAsXDims: impossible argument"-#endif-{-# INLINE patAsXDims #-}----data PatKDims (ns :: [k])- = (All KnownDim ns, Dimensions ns) => PatKDims---patKDims :: Dims ns -> PatKDims ns-patKDims U = PatKDims-patKDims (Dim :* ns) = case patKDims ns of- PatKDims -> PatKDims-#if __GLASGOW_HASKELL__ >= 802-#else-patKDims _ = error "Dims/patKDims: impossible argument"-#endif-{-# INLINE patKDims #-}
− src/Numeric/Dimensions/Fold.hs
@@ -1,334 +0,0 @@-{-# LANGUAGE PolyKinds #-}--- Workaround weird behavior of GHC 8.4-{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}--------------------------------------------------------------------------------- |--- Module : Numeric.Dimensions.Fold--- Copyright : (c) Artem Chirkin--- License : BSD3------ Maintainer : chirkin@arch.ethz.ch------ Fold a function over all dimensions provided dimension indices or offsets.--- The main purpose of this module is to fold or traverse flat data arrays--- following the shape of dimensions associated with them.----------------------------------------------------------------------------------module Numeric.Dimensions.Fold- ( overDim, overDim_, overDimIdx, overDimIdx_- , overDimOff, overDimOff_- , overDimReverse, overDimReverseIdx- , foldDim, foldDimIdx, foldDimOff- , foldDimReverse, foldDimReverseIdx- , overDimPart, overDimPartIdx- ) where---import Control.Monad ((>=>))-import Numeric.Dimensions.Idxs---- | Go over all dimensions keeping track of index and offset-overDim :: Monad m- => Dims ds -- ^ Shape of a space- -> (Idxs ds -> Int -> a -> m a) -- ^ Function to call on each dimension- -> Int -- ^ Initial offset- -> Int -- ^ Offset step- -> a -- ^ Initial value- -> m a-overDim U k offset _step = k U offset-overDim (d :* ds) k offset step = overDim ds k' offset (di * step)- where- dw = dimVal d- di = fromIntegral dw- k' is = go 1- where- go i off- | i > dw = return- | otherwise = k (Idx i :* is) off >=> go (i+1) (off+step)-{-# INLINE overDim #-}---- | Go over all dimensions in reverse order keeping track of index and offset-overDimReverse :: Monad m- => Dims ds -- ^ Shape of a space- -> (Idxs ds -> Int -> a -> m a) -- ^ Function to call on each dimension- -> Int -- ^ Initial offset- -> Int -- ^ Offset step (substracted from initial offset)- -> a -- ^ Initial value- -> m a-overDimReverse U k offset _step = k U offset-overDimReverse (d :* ds) k offset step = overDimReverse ds k' offset (di * step)- where- dw = dimVal d- di = fromIntegral dw- k' is = go dw- where- go i off- | i <= 0 = return- | otherwise = k (Idx i :* is) off >=> go (i-1) (off-step)-{-# INLINE overDimReverse #-}---- | Go over all dimensions keeping track of index and offset-overDim_ :: Monad m- => Dims ds -- ^ Shape of a space- -> (Idxs ds -> Int -> m ()) -- ^ Function to call on each dimension- -> Int -- ^ Initial offset- -> Int -- ^ Offset step- -> m ()-overDim_ U k offset _step = k U offset-overDim_ (d :* ds) k offset step = overDim_ ds k' offset (di * step)- where- dw = dimVal d- di = fromIntegral dw- k' is = go 1- where- go i off- | i > dw = return ()- | otherwise = k (Idx i :* is) off >> go (i+1) (off+step)-{-# INLINE overDim_ #-}---- | Go over all dimensions keeping track of index-overDimIdx :: Monad m- => Dims ds -- ^ Shape of a space- -> (Idxs ds -> a -> m a) -- ^ Function to call on each dimension- -> a -- ^ Initial value- -> m a-overDimIdx U k = k U-overDimIdx (d :* ds) k = overDimIdx ds k'- where- dw = dimVal d- k' is = go 1- where- go i- | i > dw = return- | otherwise = k (Idx i :* is) >=> go (i+1)-{-# INLINE overDimIdx #-}---- | Go over all dimensions keeping track of index-overDimIdx_ :: Monad m- => Dims ds -- ^ Shape of a space- -> (Idxs ds -> m ()) -- ^ Function to call on each dimension- -> m ()-overDimIdx_ U k = k U-overDimIdx_ (d :* ds) k = overDimIdx_ ds k'- where- dw = dimVal d- k' is = go 1- where- go i- | i > dw = return ()- | otherwise = k (Idx i :* is) >> go (i+1)-{-# INLINE overDimIdx_ #-}----- | Go over all dimensions keeping track of total offset-overDimOff :: Monad m- => Dims ds -- ^ Shape of a space- -> (Int -> a -> m a) -- ^ Function to call with each offset value- -> Int -- ^ Initial offset- -> Int -- ^ Offset step- -> a -- ^ Initial value- -> m a-overDimOff ds k offset step = go (totalDim ds) offset- where- go i off- | i == 0 = return- | otherwise = k off >=> go (i-1) (off+step)-{-# INLINE overDimOff #-}---- | Go over all dimensions keeping track of total offset-overDimOff_ :: Monad m- => Dims ds -- ^ Shape of a space- -> (Int -> m ()) -- ^ Function to call with each offset value- -> Int -- ^ Initial offset- -> Int -- ^ Offset step- -> m ()-overDimOff_ ds k offset step = go (totalDim ds) offset- where- go i off- | i == 0 = return ()- | otherwise = k off >> go (i-1) (off+step)-{-# INLINE overDimOff_ #-}----- | Go over all dimensions in reverse order keeping track of index-overDimReverseIdx :: Monad m- => Dims ds -- ^ Shape of a space- -> (Idxs ds -> a -> m a) -- ^ Function to call on each dimension- -> a -- ^ Initial value- -> m a-overDimReverseIdx U k = k U-overDimReverseIdx (d :* ds) k = overDimReverseIdx ds k'- where- dw = dimVal d- k' is = go dw- where- go i- | i <= 0 = return- | otherwise = k (Idx i :* is) >=> go (i-1)-{-# INLINE overDimReverseIdx #-}------ | Fold over all dimensions keeping track of index and offset-foldDim :: Dims ds -- ^ Shape of a space- -> (Idxs ds -> Int -> a -> a) -- ^ Function to call on each dimension- -> Int -- ^ Initial offset- -> Int -- ^ Offset step- -> a -- ^ Initial value- -> a-foldDim U k offset _step = k U offset-foldDim (d :* ds) k offset step = foldDim ds k' offset (di * step)- where- dw = dimVal d- di = fromIntegral dw- k' is = go 1- where- go i off- | i > dw = id- | otherwise = go (i+1) (off+step) . k (Idx i :* is) off-{-# INLINE foldDim #-}---- | Fold over all dimensions in reverse order keeping track of index and offset-foldDimReverse :: Dims ds -- ^ Shape of a space- -> (Idxs ds -> Int -> a -> a) -- ^ Function to call on each dimension- -> Int -- ^ Initial offset- -> Int -- ^ Offset step (substracted from initial offset)- -> a -- ^ Initial value- -> a-foldDimReverse U k offset _step = k U offset-foldDimReverse (d :* ds) k offset step = foldDimReverse ds k' offset (di * step)- where- dw = dimVal d- di = fromIntegral dw- k' is = go dw- where- go i off- | i <= 0 = id- | otherwise = go (i-1) (off-step) . k (Idx i :* is) off-{-# INLINE foldDimReverse #-}------ | Fold over all dimensions keeping track of index-foldDimIdx :: Dims ds -- ^ Shape of a space- -> (Idxs ds -> a -> a) -- ^ Function to call on each dimension- -> a -- ^ Initial value- -> a-foldDimIdx U k = k U-foldDimIdx (d :* ds) k = foldDimIdx ds k'- where- dw = dimVal d- k' is = go 1- where- go i- | i > dw = id- | otherwise = go (i+1) . k (Idx i :* is)-{-# INLINE foldDimIdx #-}----- | Fold over all dimensions keeping track of total offset-foldDimOff :: Dims ds -- ^ Shape of a space- -> (Int -> a -> a) -- ^ Function to call on each dimension- -> Int -- ^ Initial offset- -> Int -- ^ Offset step- -> a -- ^ Initial value- -> a-foldDimOff ds k offset step = go (totalDim ds) offset- where- go i off- | i == 0 = id- | otherwise = go (i-1) (off+step) . k off-{-# INLINE foldDimOff #-}----- | Fold over all dimensions in reverse order keeping track of index-foldDimReverseIdx :: Dims ds -- ^ Shape of a space- -> (Idxs ds -> a -> a) -- ^ Function to call on each dimension- -> a -- ^ Initial value- -> a-foldDimReverseIdx U k = k U-foldDimReverseIdx (d :* ds) k = foldDimReverseIdx ds k'- where- dw = dimVal d- k' is = go dw- where- go i- | i <= 0 = id- | otherwise = go (i-1) . k (Idx i :* is)-{-# INLINE foldDimReverseIdx #-}----- | Traverse from the first index to the second index in each dimension.--- You can combine positive and negative traversal directions--- along different dimensions.------ Note, initial and final indices are included in the range;--- the argument function is guaranteed to execute at least once.-overDimPart :: (Dimensions ds, Monad m)- => Idxs ds -- ^ Initial indices- -> Idxs ds -- ^ Final indices- -> (Idxs ds -> Int -> a -> m a)- -- ^ Function to call on each dimension- -> Int -- ^ Initial offset (at index @minBound :: Idxs ds@)- -- Note, this is not an offset value at initial indices.- -> Int -- ^ Offset step- -> a -- ^ initial value- -> m a-overDimPart imin imax f offset step = overDimPart' stepSizes imin imax f offset- where- stepSizes = createStepSizes (dims `inSpaceOf` imin) step-- createStepSizes :: Dims ns -> Int -> TypedList StepSize ns- createStepSizes U _ = U- createStepSizes (d :* ds) k- = StepSize k :* createStepSizes ds (k * fromIntegral (dimVal d))--overDimPart' :: Monad m- => TypedList StepSize ns- -> Idxs ds -> Idxs ds- -> (Idxs ds -> Int -> a -> m a)- -> Int- -> a -> m a-overDimPart' U U U k off0 = k U off0-overDimPart' (siW :* iws) (Idx iStart :* starts) (Idx iEnd :* ends) k off0- | iEnd >= iStart = overDimPart' iws starts ends (loop iStart) (off0 + headOff)- | otherwise = overDimPart' iws starts ends (looi iStart) (off0 + headOff)- where- StepSize iW = siW- headOff = iW * (fromIntegral iStart - 1)- loop i js off- | i > iEnd = return- | otherwise = k (Idx i :* js) off >=> loop (i+1) js (off + iW)- looi i js off- | i < iEnd = return- | otherwise = k (Idx i :* js) off >=> looi (i-1) js (off - iW)---newtype StepSize n = StepSize Int---- | Traverse from the first index to the second index in each dimension.--- You can combine positive and negative traversal directions--- along different dimensions.------ Note, initial and final indices are included in the range;--- the argument function is guaranteed to execute at least once.-overDimPartIdx :: Monad m- => Idxs ds -- ^ Initial indices- -> Idxs ds -- ^ Final indices- -> (Idxs ds -> a -> m a)- -- ^ Function to call on each dimension- -> a -- ^ initial value- -> m a-overDimPartIdx U U k = k U-overDimPartIdx (start :* starts) (end :* ends) k- | iEnd >= iStart = overDimPartIdx starts ends (loop iStart)- | otherwise = overDimPartIdx starts ends (looi iStart)- where- Idx iStart = start- Idx iEnd = end- loop i is- | i > iEnd = return- | otherwise = k (Idx i :* is) >=> loop (i+1) is- looi i is- | i < iEnd = return- | otherwise = k (Idx i :* is) >=> looi (i-1) is
+ src/Numeric/Dimensions/Idx.hs view
@@ -0,0 +1,483 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE ExplicitNamespaces #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE UndecidableInstances #-}++-----------------------------------------------------------------------------+-- |+-- Module : Numeric.Dimensions.Idx+-- Copyright : (c) Artem Chirkin+-- License : BSD3+--+--+-- Provides a data type `Idx` to index `Dim` and `Idxs`+-- that enumerates through multiple dimensions.+--+-- Higher indices go first, i.e. assumed enumeration+-- is i = i1*n1*n2*...*n(k-1) + ... + i(k-2)*n1*n2 + i(k-1)*n1 + ik+-- This corresponds to row-first layout of matrices and multidimenional arrays.+--+-----------------------------------------------------------------------------++module Numeric.Dimensions.Idx+ ( -- * Data types+ Idx (Idx), Idxs+ , idxFromWord, unsafeIdxFromWord, idxToWord+ , listIdxs, idxsFromWords+ ) where+++import Data.Coerce+import Data.Constraint (Dict (..))+import Data.Data (Data)+import Foreign.Storable (Storable)+import GHC.Enum+import GHC.Generics (Generic)+import qualified Text.Read as P++#ifdef UNSAFE_INDICES+import GHC.Base (Int (..), Type, Word (..), int2Word#, unsafeCoerce#, word2Int#)+#else+import GHC.Base (Int (..), Type, Word (..), int2Word#, maxInt, plusWord2#,+ timesWord2#, unsafeCoerce#, word2Int#)+#endif++import Numeric.Dimensions.Dim+import Numeric.TypedList (typedListReadPrec, typedListShowsPrec)+++-- | This type is used to index a single dimension;+-- the range of indices is from @0@ to @n-1@.+--+newtype Idx (n :: k) = Idx' Word+ deriving ( Data, Generic, Integral, Real, Storable, Eq, Ord )+++-- | Convert between `Word` and `Idx`.+--+-- If the word is outside of the bounds, fails with an error+-- (unless @unsafeindices@ flag is turned on).+--+pattern Idx :: forall (k :: Type) (n :: k) . BoundedDim n => Word -> Idx n+pattern Idx w <- Idx' w+ where+ Idx = unsafeIdxFromWord+{-# COMPLETE Idx #-}++-- | Type-level dimensional indexing with arbitrary Word values inside.+-- Most of the operations on it require `Dimensions` constraint,+-- because the @Idxs@ itself does not store info about dimension bounds.+type Idxs (xs :: [k]) = TypedList Idx xs++-- | Convert an arbitrary Word to @Idx@.+--+-- If the word is outside of the bounds, fails with an error+-- (unless @unsafeindices@ flag is turned on).+--+unsafeIdxFromWord :: forall (k :: Type) (d :: k) . BoundedDim d => Word -> Idx d+#ifdef UNSAFE_INDICES+unsafeIdxFromWord = coerce+#else+unsafeIdxFromWord w+ | w < d = coerce w+ | otherwise = errorWithoutStackTrace+ $ "idxFromWord{" ++ showIdxType @k @d ++ "}: word "+ ++ show w ++ " is outside of index bounds."+ where+ d = dimVal (dimBound @k @d)+#endif+{-# INLINE unsafeIdxFromWord #-}++-- | Convert an arbitrary Word to @Idx@.+idxFromWord :: forall (k :: Type) (d :: k) . BoundedDim d => Word -> Maybe (Idx d)+idxFromWord w+ | w < dimVal (dimBound @k @d) = Just (coerce w)+ | otherwise = Nothing+{-# INLINE idxFromWord #-}++-- | Get the value of an @Idx@.+idxToWord :: forall (k :: Type) (d :: k) . Idx d -> Word+idxToWord = coerce+{-# INLINE idxToWord #-}++{-# RULES+"fromIntegral/idxToWord"+ fromIntegral = idxToWord+ #-}++listIdxs :: forall (k :: Type) (xs :: [k]) . Idxs xs -> [Word]+listIdxs = unsafeCoerce#+{-# INLINE listIdxs #-}++idxsFromWords :: forall (k :: Type) (xs :: [k])+ . BoundedDims xs => [Word] -> Maybe (Idxs xs)+idxsFromWords = unsafeCoerce# . go (listDims (dimsBound @k @xs))+ where+ go :: [Word] -> [Word] -> Maybe [Word]+ go [] [] = Just []+ go (d : ds) (i : is)+ | i < d = (i:) <$> go ds is+ go _ _ = Nothing++++instance BoundedDim x => Read (Idx (x :: k)) where+ readPrec = do+ w <- P.readPrec+ if w < dimVal (dimBound @k @x)+ then return (Idx' w)+ else P.pfail+ readList = P.readListDefault+ readListPrec = P.readListPrecDefault++instance Show (Idx (x :: k)) where+ showsPrec = coerce (showsPrec :: Int -> Word -> ShowS)++instance BoundedDim n => Bounded (Idx (n :: k)) where+ minBound = 0+ {-# INLINE minBound #-}+ maxBound = coerce (dimVal(dimBound @k @n) - 1)+ {-# INLINE maxBound #-}++instance BoundedDim n => Enum (Idx (n :: k)) where++#ifdef UNSAFE_INDICES+ succ = coerce ((+ 1) :: Word -> Word)+#else+ succ x@(Idx' i)+ | x < maxBound = coerce (i + 1)+ | otherwise = succError $ showIdxType @k @n+#endif+ {-# INLINE succ #-}++#ifdef UNSAFE_INDICES+ pred = coerce (subtract 1 :: Word -> Word)+#else+ pred x@(Idx' i)+ | x > minBound = coerce (i - 1)+ | otherwise = predError $ showIdxType @k @n+#endif+ {-# INLINE pred #-}++#ifdef UNSAFE_INDICES+ toEnum (I# i#) = coerce (W# (int2Word# i#))+#else+ toEnum i+ | i >= 0 && i' < d = coerce i'+ | otherwise = toEnumError (showIdxType @k @n) i (0, d - 1)+ where+ d = dimVal (dimBound @k @n)+ i' = fromIntegral i+#endif+ {-# INLINE toEnum #-}++#ifdef UNSAFE_INDICES+ fromEnum (Idx' (W# w#)) = I# (word2Int# w#)+#else+ fromEnum (Idx' x@(W# w#))+ | x <= maxIntWord = I# (word2Int# w#)+ | otherwise = fromEnumError (showIdxType @k @n) x+ where+ maxIntWord = W# (case maxInt of I# i -> int2Word# i)+#endif+ {-# INLINE fromEnum #-}++ enumFrom (Idx' n)+ = coerce (enumFromTo n (dimVal (dimBound @k @n) - 1))+ {-# INLINE enumFrom #-}+ enumFromThen (Idx' n0) (Idx' n1)+ = coerce (enumFromThenTo n0 n1 lim)+ where+ lim = if n1 >= n0 then dimVal (dimBound @k @n) - 1 else 0+ {-# INLINE enumFromThen #-}+ enumFromTo+ = coerce (enumFromTo :: Word -> Word -> [Word])+ {-# INLINE enumFromTo #-}+ enumFromThenTo+ = coerce (enumFromThenTo :: Word -> Word -> Word -> [Word])+ {-# INLINE enumFromThenTo #-}++instance BoundedDim n => Num (Idx (n :: k)) where++#ifdef UNSAFE_INDICES+ (+) = coerce ((+) :: Word -> Word -> Word)+#else+ (Idx' a@(W# a#)) + b@(Idx' (W# b#))+ | ovf || r >= d+ = errorWithoutStackTrace+ $ "Num.(+){" ++ showIdxType @k @n ++ "}: sum of "+ ++ show a ++ " and " ++ show b+ ++ " is outside of index bounds."+ | otherwise = coerce r+ where+ (ovf, r) = case plusWord2# a# b# of+ (# r2#, r1# #) -> ( W# r2# > 0 , W# r1# )+ d = dimVal (dimBound @k @n)+#endif+ {-# INLINE (+) #-}++#ifdef UNSAFE_INDICES+ (-) = coerce ((-) :: Word -> Word -> Word)+#else+ (Idx' a) - (Idx' b)+ | b > a+ = errorWithoutStackTrace+ $ "Num.(-){" ++ showIdxType @k @n ++ "}: difference of "+ ++ show a ++ " and " ++ show b+ ++ " is negative."+ | otherwise = coerce (a - b)+#endif+ {-# INLINE (-) #-}++#ifdef UNSAFE_INDICES+ (*) = coerce ((*) :: Word -> Word -> Word)+#else+ (Idx' a@(W# a#)) * b@(Idx' (W# b#))+ | ovf || r >= d+ = errorWithoutStackTrace+ $ "Num.(*){" ++ showIdxType @k @n ++ "}: product of "+ ++ show a ++ " and " ++ show b+ ++ " is outside of index bounds."+ | otherwise = coerce r+ where+ (ovf, r) = case timesWord2# a# b# of+ (# r2#, r1# #) -> ( W# r2# > 0 , W# r1# )+ d = dimVal (dimBound @k @n)+#endif+ {-# INLINE (*) #-}++ negate = errorWithoutStackTrace+ $ "Num.(*){" ++ showIdxType @k @n ++ "}: cannot negate index."+ {-# INLINE negate #-}+ abs = id+ {-# INLINE abs #-}+ signum = const (Idx' 1)+ {-# INLINE signum #-}++#ifdef UNSAFE_INDICES+ fromInteger = coerce (fromInteger :: Integer -> Word)+#else+ fromInteger i+ | i >= 0 && i < d = Idx' $ fromInteger i+ | otherwise = errorWithoutStackTrace+ $ "Num.fromInteger{" ++ showIdxType @k @n ++ "}: integer "+ ++ show i ++ " is outside of index bounds."+ where+ d = toInteger $ dimVal (dimBound @k @n)+#endif+ {-# INLINE fromInteger #-}+++++instance Eq (Idxs (xs :: [k])) where+ (==) = unsafeCoerce# ((==) :: [Word] -> [Word] -> Bool)+ {-# INLINE (==) #-}++-- | Compare indices by their importance in lexicorgaphic order+-- from the first dimension to the last dimension+-- (the first dimension is the most significant one).+--+-- Literally,+--+-- > compare a b = compare (listIdxs a) (listIdxs b)+--+-- This is the same @compare@ rule, as for `Dims`.+-- This is also consistent with offsets:+--+-- > sort == sortOn fromEnum+--+instance Ord (Idxs (xs :: [k])) where+ compare = unsafeCoerce# (compare :: [Word] -> [Word] -> Ordering)+ {-# INLINE compare #-}++instance Show (Idxs (xs :: [k])) where+ showsPrec = typedListShowsPrec @k @Idx @xs showsPrec++instance BoundedDims xs => Read (Idxs (xs :: [k])) where+ readPrec = case inferAllBoundedDims @k @xs of+ Dict -> typedListReadPrec @k @BoundedDim ":*" P.readPrec (tList @k @xs)+ readList = P.readListDefault+ readListPrec = P.readListPrecDefault++-- | With this instance we can slightly reduce indexing expressions, e.g.+--+-- > x ! (1 :* 2 :* 4) == x ! (1 :* 2 :* 4 :* U)+--+instance BoundedDim n => Num (Idxs '[(n :: k)]) where+ (a:*U) + (b:*U) = (a+b) :* U+ {-# INLINE (+) #-}+ (a:*U) - (b:*U) = (a-b) :* U+ {-# INLINE (-) #-}+ (a:*U) * (b:*U) = (a*b) :* U+ {-# INLINE (*) #-}+ signum (a:*U) = signum a :* U+ {-# INLINE signum #-}+ abs (a:*U) = abs a :* U+ {-# INLINE abs #-}+ fromInteger i = fromInteger i :* U+ {-# INLINE fromInteger #-}++instance BoundedDims ds => Bounded (Idxs (ds :: [k])) where+ maxBound = f (minDims @k @ds)+ where+ f :: forall (ns :: [k]) . Dims ns -> Idxs ns+ f U = U+ f (d :* ds) = coerce (dimVal d - 1) :* f ds+ {-# INLINE maxBound #-}+ minBound = f (minDims @k @ds)+ where+ f :: forall (ns :: [k]) . Dims ns -> Idxs ns+ f U = U+ f (_ :* ds) = Idx' 0 :* f ds+ {-# INLINE minBound #-}++-- @ds@ must be @[Nat]@ for @Enum (Idxs ds)@,+-- because succ and pred would break otherwise+instance Dimensions ds => Enum (Idxs (ds :: [Nat])) where++ succ idx = case go dds idx of+ (True , _ ) -> succError $ showIdxsType dds+ (False, i') -> i'+ where+ dds = dims @ds+ go :: forall (ns :: [Nat]) . Dims ns -> Idxs ns -> (Bool, Idxs ns)+ go U U = (True, U)+ go (d :* ds) (Idx' i :* is) = case go ds is of+ (True , is')+ | i + 1 == dimVal d -> (True , Idx' 0 :* is')+ | otherwise -> (False, Idx' (i+1) :* is')+ (False, is') -> (False, Idx' i :* is')+ {-# INLINE succ #-}++ pred idx = case go dds idx of+ (True , _ ) -> predError $ showIdxsType dds+ (False, i') -> i'+ where+ dds = dims @ds+ go :: forall (ns :: [Nat]) . Dims ns -> Idxs ns -> (Bool, Idxs ns)+ go U U = (True, U)+ go (d :* ds) (Idx' i :* is) = case go ds is of+ (True , is')+ | i == 0 -> (True , Idx' (dimVal d - 1) :* is')+ | otherwise -> (False, Idx' (i-1) :* is')+ (False, is') -> (False, Idx' i :* is')+ {-# INLINE pred #-}++ toEnum off0 = case go dds of+ (0, i) -> i+ _ -> toEnumError (showIdxsType dds) off0 (0, totalDim dds - 1)+ where+ dds = dims @ds+ go :: forall (ns :: [Nat]) . Dims ns -> (Word, Idxs ns)+ go U = (fromIntegral off0, U)+ go (d :* ds)+ | (off , is) <- go ds+ , (off', i ) <- quotRem off (dimVal d)+ = (off', Idx' i :* is)+ {-# INLINE toEnum #-}++ fromEnum = fromIntegral . snd+ . foldr f (1, 0)+ . zip (listDims $ dims @ds) . listIdxs+ where+ f :: (Word, Word) -> (Word, Word) -> (Word, Word)+ f (d, i) (td, off) = (d * td, off + td * i)+ {-# INLINE fromEnum #-}++ enumFrom = unsafeCoerce# go True (dims @ds)+ where+ go :: Bool -> [Word] -> [Word] -> [[Word]]+ go b (d:ds) (i:is) =+ [ i' : is' | (b', i') <- zip (b : repeat False)+ $ enumFromTo (if b then i else 0) (d - 1)+ , is' <- go b' ds is ]+ go _ _ _ = [[]]+ {-# INLINE enumFrom #-}++ enumFromTo = unsafeCoerce# go True True (dims @ds)+ where+ go :: Bool -> Bool -> [Word] -> [Word] -> [Word] -> [[Word]]+ go bl bu (d:ds) (x:xs) (y:ys) =+ [ i : is | (bl', bu', i) <- prepapp bl bu+ $ enumFromTo (if bl then x else 0)+ (if bu then y else d - 1)+ , is <- go bl' bu' ds xs ys ]+ go _ _ _ _ _ = [[]]+ prepapp _ _ [] = []+ prepapp bl bu [i] = [(bl, bu, i)]+ prepapp bl bu (i:is) = (bl, False, i :: Word) : app bu is+ app _ [] = []+ app bu [i] = [(False, bu, i :: Word)]+ app bu (i:is) = (False, False, i) : app bu is+ {-# INLINE enumFromTo #-}++ enumFromThen x0 x1 = case compare x1 x0 of+ EQ -> repeat x0+ GT -> enumFromThenTo x0 x1 maxBound+ LT -> enumFromThenTo x0 x1 minBound+ {-# INLINE enumFromThen #-}++ enumFromThenTo x0 x1 y = case dir of+ EQ -> if allYs >= allX0s then repeat x0 else []+ GT -> let (_, allDXs) = idxMinus allDs allX0s allX1s+ repeatStep is+ = if is <= allYs+ then is : case idxPlus allDs is allDXs of+ (0, is') -> repeatStep is'+ _ -> []+ else []+ in unsafeCoerce# (repeatStep allX0s)+ LT -> let (_, allDXs) = idxMinus allDs allX1s allX0s+ repeatStep is+ = if is >= allYs+ then is : case idxMinus allDs allDXs is of+ (0, is') -> repeatStep is'+ _ -> []+ else []+ in unsafeCoerce# (repeatStep allX0s)+ where+ allDs = listDims $ dims @ds+ allX0s = listIdxs x0+ allX1s = listIdxs x1+ allYs = listIdxs y+ dir = compare allX1s allX0s -- succ or pred?+ -- second arg minus first arg+ idxMinus :: [Word] -> [Word] -> [Word] -> (Word, [Word])+ idxMinus (d:ds) (a:as) (b:bs)+ = let (one , xs ) = idxMinus ds as bs+ (one', x ) = quotRem (d + b - a - one) d+ in (1 - one', x : xs)+ idxMinus _ _ _ = (0, [])+ idxPlus :: [Word] -> [Word] -> [Word] -> (Word, [Word])+ idxPlus (d:ds) (a:as) (b:bs)+ = let (one , xs ) = idxPlus ds as bs+ (one', x ) = quotRem (a + b + one) d+ in (one', x : xs)+ idxPlus _ _ _ = (0, [])+ {-# INLINE enumFromThenTo #-}++++-- | Show type of Idx (for displaying nice errors).+showIdxType :: forall (k :: Type) (x :: k) . BoundedDim x => String+showIdxType = "Idx " ++ show (dimVal (dimBound @k @x))++-- | Show type of Idxs (for displaying nice errors).+showIdxsType :: Dims ns -> String+showIdxsType ds = "Idxs '" ++ show (listDims ds)
− src/Numeric/Dimensions/Idxs.hs
@@ -1,427 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE ExplicitNamespaces #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE MagicHash #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE Strict #-}-{-# LANGUAGE TypeApplications #-}-#if __GLASGOW_HASKELL__ >= 802-#else-{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}-#endif--------------------------------------------------------------------------------- |--- Module : Numeric.Dimensions.Idxs--- Copyright : (c) Artem Chirkin--- License : BSD3------ Maintainer : chirkin@arch.ethz.ch------ Provides a data type Idx that enumerates through multiple dimensions.--- Lower indices go first, i.e. assumed enumeration--- is i = i1 + i2*n1 + i3*n1*n2 + ... + ik*n1*n2*...*n(k-1).--- This is also to encourage column-first matrix enumeration and array layout.-----------------------------------------------------------------------------------module Numeric.Dimensions.Idxs- ( -- * Data types- Idx (..), Idxs- , idxFromWord, unsafeIdxFromWord, idxToWord- , listIdxs, idxsFromWords- -- * Re-export dimensions types- , module Numeric.Dimensions.Dims- ) where---import Control.Arrow (first)-import Data.Data (Data)-import Foreign.Storable (Storable)-import GHC.Base-import GHC.Enum-import GHC.Generics (Generic, Generic1)--import Numeric.Dimensions.Dims----- | This type is used to index a single dimension;--- the range of indices is from @1@ to @n@.------ Note, this type has a weird `Enum` instance:------ >>>fromEnum (Idx 7)--- 6------ The logic behind this is that the `Enum` class is used to transform--- indices to offsets. That is, element of an array at index @k :: Idx n@--- is the element taken by an offset `k - 1 :: Int`.-newtype Idx n = Idx { unIdx :: Word }- deriving ( Data, Generic, Generic1, Integral, Real, Storable, Eq, Ord )--instance Read (Idx n) where- readsPrec d = fmap (first Idx) . readsPrec d--instance Show (Idx n) where- showsPrec d = showsPrec d . unIdx---instance KnownDim n => Bounded (Idx n) where- minBound = 1- {-# INLINE minBound #-}- maxBound = unsafeCoerce# (dim @_ @n)- {-# INLINE maxBound #-}---- This is a weird `Enum` instance:------ >>>fromEnum (Idx 7)--- 6------ The logic behind this is that the `Enum` class is used to transform--- indices to offsets. That is, element of an array at index @k :: Idx n@--- is the element taken by an offset `k - 1 :: Int`.-instance KnownDim n => Enum (Idx n) where--#ifdef UNSAFE_INDICES- succ = unsafeCoerce# ((+ 1) :: Word -> Word)-#else- succ x@(Idx i)- | x /= maxBound = Idx (i + 1)- | otherwise = succError $ "Idx " ++ show (dim @_ @n)-#endif- {-# INLINE succ #-}--#ifdef UNSAFE_INDICES- pred = unsafeCoerce# ((+ (-1)) :: Word -> Word)-#else- pred x@(Idx i)- | x /= maxBound = Idx (i + 1)- | otherwise = predError $ "Idx " ++ show (dim @_ @n)-#endif- {-# INLINE pred #-}--#ifdef UNSAFE_INDICES- toEnum (I# i#) = unsafeCoerce# (W# (int2Word# (i# +# 1#)))-#else- toEnum i@(I# i#)- | i >= 0 && i < dm = unsafeCoerce# (W# (int2Word# (i# +# 1#) ))- | otherwise = toEnumError ("Idx " ++ show d) i (0, dm)- where- d = unsafeCoerce# (dim @_ @n) :: Word- dm = fromIntegral d - 1-#endif- {-# INLINE toEnum #-}--#ifdef UNSAFE_INDICES- fromEnum (Idx (W# w#)) = I# (word2Int# w# -# 1#)-#else- fromEnum (Idx x@(W# w#))- | x <= maxIntWord = I# (word2Int# w# -# 1#)- | otherwise = fromEnumError ("Idx " ++ show (dim @_ @n)) x- where- maxIntWord = W# (case maxInt of I# i -> int2Word# i)-#endif- {-# INLINE fromEnum #-}-- enumFrom (Idx n)- = unsafeCoerce# (enumFromTo n (unsafeCoerce# (dim @_ @n)))- {-# INLINE enumFrom #-}- enumFromThen (Idx n0) (Idx n1)- = case compare n0 n1 of- LT -> unsafeCoerce# (enumFromThenTo n0 n1 (unsafeCoerce# (dim @_ @n)))- EQ -> unsafeCoerce# (repeat n0)- GT -> unsafeCoerce# (enumFromThenTo n0 n1 1)- {-# INLINE enumFromThen #-}- enumFromTo- = unsafeCoerce# (enumFromTo :: Word -> Word -> [Word])- {-# INLINE enumFromTo #-}- enumFromThenTo- = unsafeCoerce# (enumFromThenTo :: Word -> Word -> Word -> [Word])- {-# INLINE enumFromThenTo #-}--instance KnownDim n => Num (Idx n) where--#ifdef UNSAFE_INDICES- (+) = unsafeCoerce# ((+) :: Word -> Word -> Word)-#else- (Idx a) + (Idx b)- | r > d || r < a || r < b- = errorWithoutStackTrace- $ "Num.(+){Idx " ++ show d ++ "}: sum of "- ++ show a ++ " and " ++ show b- ++ " is outside of index bounds."- | otherwise = Idx r- where- r = a + b- d = unsafeCoerce# (dim @_ @n)-#endif- {-# INLINE (+) #-}--#ifdef UNSAFE_INDICES- (-) = unsafeCoerce# ((-) :: Word -> Word -> Word)-#else- (Idx a) - (Idx b)- | b >= a- = errorWithoutStackTrace- $ "Num.(-){Idx " ++ show (dim @_ @n) ++ "}: difference of "- ++ show a ++ " and " ++ show b- ++ " is not positive."- | otherwise = Idx (a - b)-#endif- {-# INLINE (-) #-}--#ifdef UNSAFE_INDICES- (*) = unsafeCoerce# ((*) :: Word -> Word -> Word)-#else- (Idx a) * (Idx b)- | r > d || r < a || r < b- = errorWithoutStackTrace- $ "Num.(*){Idx " ++ show d ++ "}: product of "- ++ show a ++ " and " ++ show b- ++ " is outside of index bounds."- | otherwise = Idx r- where- r = a * b- d = unsafeCoerce# (dim @_ @n)-#endif- {-# INLINE (*) #-}-- negate = errorWithoutStackTrace- $ "Num.(*){Idx " ++ show (dim @_ @n) ++ "}: cannot negate index."- {-# INLINE negate #-}- abs = id- {-# INLINE abs #-}- signum _ = Idx 1- {-# INLINE signum #-}--#ifdef UNSAFE_INDICES- fromInteger = unsafeCoerce# (fromInteger :: Integer -> Word)-#else- fromInteger i- | i > 0 && i <= d = Idx $ fromInteger i- | otherwise = errorWithoutStackTrace- $ "Num.fromInteger{Idx "- ++ show d ++ "}: integer "- ++ show i ++ " is outside of index bounds."- where- d = toInteger (unsafeCoerce# (dim @_ @n) :: Word)-#endif- {-# INLINE fromInteger #-}---unsafeIdxFromWord :: forall d . KnownDim d => Word -> Idx d-#ifdef UNSAFE_INDICES-unsafeIdxFromWord = unsafeCoerce#-#else-unsafeIdxFromWord w- | w > 0 && w <= d = Idx w- | otherwise = errorWithoutStackTrace- $ "idxFromWord{Idx "- ++ show d ++ "}: word "- ++ show w ++ " is outside of index bounds."- where- d = unsafeCoerce# (dim @_ @d)-#endif-{-# INLINE unsafeIdxFromWord #-}--idxFromWord :: forall d . KnownDim d => Word -> Maybe (Idx d)-idxFromWord w- | w > 0 && w <= unsafeCoerce# (dim @_ @d) = Just (Idx w)- | otherwise = Nothing-{-# INLINE idxFromWord #-}---idxToWord :: Idx d -> Word-idxToWord = unsafeCoerce#-{-# INLINE idxToWord #-}--{-# RULES-"fromIntegral/idxToWord"- fromIntegral = idxToWord- #-}----- | Type-level dimensional indexing with arbitrary Word values inside.--- Most of the operations on it require `Dimensions` constraint,--- because the @Idxs@ itself does not store info about dimension bounds.------ Note, this type has a special `Enum` instance:--- `fromEnum` gives an offset of the index in a flat 1D array;--- this is in line with a weird `Enum` instance of `Idx` type.-type Idxs (xs :: [k]) = TypedList Idx xs---listIdxs :: Idxs xs -> [Word]-listIdxs = unsafeCoerce#-{-# INLINE listIdxs #-}---idxsFromWords :: forall ds . Dimensions ds => [Word] -> Maybe (Idx ds)-idxsFromWords = unsafeCoerce# . go (listDims (dims @_ @ds))- where- go [] [] = Just []- go (d : ds) (i : is)- | i > 0 && i <= d = (i:) <$> go ds is- go _ _ = Nothing----instance Eq (Idxs xs) where- (==) = unsafeCoerce# ((==) :: [Word] -> [Word] -> Bool)- {-# INLINE (==) #-}---- | Compare indices by their importance in lexicorgaphic order--- from the last dimension to the first dimension--- (the last dimension is the most significant one) @O(Length xs)@.------ Literally,------ > compare a b = compare (reverse $ listIdxs a) (reverse $ listIdxs b)------ This is the same @compare@ rule, as for `Dims`.--- Another reason to reverse the list of indices is to have a consistent--- behavior when calculating index offsets:------ > sort == sortOn fromEnum----instance Ord (Idxs xs) where- compare a b = compare (reverse $ listIdxs a) (reverse $ listIdxs b)- {-# INLINE compare #-}---instance Show (Idxs xs) where- show ds = "Idxs " ++ show (listIdxs ds)- showsPrec p ds- = showParen (p >= 10)- $ showString "Idxs " . showsPrec p (listIdxs ds)---- | With this instance we can slightly reduce indexing expressions, e.g.------ > x ! (1 :* 2 :* 4) == x ! (1 :* 2 :* 4 :* U)----instance KnownDim n => Num (Idxs '[n]) where- (a:*U) + (b:*U) = (a+b) :* U- {-# INLINE (+) #-}- (a:*U) - (b:*U) = (a-b) :* U- {-# INLINE (-) #-}- (a:*U) * (b:*U) = (a*b) :* U- {-# INLINE (*) #-}- signum (a:*U) = signum a :* U- {-# INLINE signum #-}- abs (a:*U) = abs a :* U- {-# INLINE abs #-}- fromInteger i = fromInteger i :* U- {-# INLINE fromInteger #-}--instance Dimensions ds => Bounded (Idxs ds) where- maxBound = f (dims @_ @ds)- where- f :: forall ns . Dims ns -> Idxs ns- f U = U- f (d :* ds) = Idx (dimVal d) :* f ds- {-# INLINE maxBound #-}- minBound = f (dims @_ @ds)- where- f :: forall ns . Dims ns -> Idxs ns- f U = U- f (_ :* ds) = Idx 1 :* f ds- {-# INLINE minBound #-}---instance Dimensions ds => Enum (Idxs ds) where-- succ = go (dims @_ @ds)- where- go :: forall ns . Dims ns -> Idxs ns -> Idxs ns- go U U = succError $ "Idxs " ++ show (listDims $ dims @_ @ds)- go (d :* ds) (Idx i :* is)- | i == dimVal d = Idx 1 :* go ds is- | otherwise = Idx (i+1) :* is- {-# INLINE succ #-}-- pred = go (dims @_ @ds)- where- go :: forall ns . Dims ns -> Idxs ns -> Idxs ns- go U U = predError $ "Idxs " ++ show (listDims $ dims @_ @ds)- go (d :* ds) (Idx i :* is)- | i == 1 = Idx (dimVal d) :* go ds is- | otherwise = Idx (i-1) :* is- {-# INLINE pred #-}-- toEnum i = go dds $ fromIntegral i- where- dds = dims @_ @ds- go :: forall ns . Dims ns -> Word -> Idxs ns- go U 0 = U- go U _ = toEnumError ("Idxs " ++ show (listDims dds))- i (0, totalDim dds - 1)- go (d :* ds) off = case divMod off (dimVal d) of- (off', j) -> Idx (j+1) :* go ds off'- {-# INLINE toEnum #-}-- fromEnum = fromIntegral . go 1 (dims @_ @ds)- where- go :: forall ns . Word -> Dims ns -> Idxs ns -> Word- go _ U U = 0- go m (d :* ds) (Idx i :* is) = m * (i - 1) + go (m * dimVal d) ds is- {-# INLINE fromEnum #-}-- enumFrom x = take (diffIdx (dims @_ @ds) maxBound x + 1) $ iterate succ x- {-# INLINE enumFrom #-}-- enumFromTo x y | x >= y = take (diffIdx ds x y + 1) $ iterate pred x- | otherwise = take (diffIdx ds y x + 1) $ iterate succ x- where- ds = dims @_ @ds- {-# INLINE enumFromTo #-}-- enumFromThen x x' = take n $ iterate (stepIdx ds dn) x- where- ds = dims @_ @ds- dn = diffIdx ds x' x- n = 1 + if dn == 0- then 0- else if dn > 0- then diffIdx ds maxBound x `div` dn- else diffIdx ds x minBound `div` negate dn- {-# INLINE enumFromThen #-}-- enumFromThenTo x x' y = take n $ iterate (stepIdx ds dn) x- where- ds = dims @_ @ds- dn = diffIdx ds x' x- n = 1 + if dn == 0 then 0- else diffIdx ds y x `div` dn- {-# INLINE enumFromThenTo #-}------------------------------------------------------------------------------------------ | Offset difference of two indices @idx1 - idx2@-diffIdx :: Dims xs -> Idxs xs -> Idxs xs -> Int-diffIdx U U U = 0-diffIdx (d :* ds) (Idx i1 :* is1) (Idx i2 :* is2)- = fromIntegral i1 - fromIntegral i2- + fromIntegral (dimVal d) * diffIdx ds is1 is2-{-# INLINE diffIdx #-}---- | Step dimension index by an Int offset-stepIdx :: Dims ds -> Int -> Idxs ds -> Idxs ds-stepIdx U _ U = U-stepIdx (d :* ds) di (Idx i :* is)- = case divMod (di + fromIntegral i - 1) (fromIntegral (dimVal d)) of- (0 , i') -> Idx (fromIntegral (i'+1)) :* is- (di', i') -> Idx (fromIntegral (i'+1)) :* stepIdx ds di' is-{-# INLINE stepIdx #-}
src/Numeric/Tuple.hs view
@@ -1,23 +1,20 @@ {-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-} ----------------------------------------------------------------------------- -- | -- Module : Numeric.Tuple -- Copyright : (c) Artem Chirkin -- License : BSD3 ----- Maintainer : chirkin@arch.ethz.ch ----- ----------------------------------------------------------------------------- module Numeric.Tuple ( module TS , toStrict, fromStrict ) where -import Numeric.Tuple.Strict as TS-import qualified Numeric.Tuple.Lazy as TL-import Unsafe.Coerce (unsafeCoerce)+import qualified Numeric.Tuple.Lazy as TL+import Numeric.Tuple.Strict as TS+import Unsafe.Coerce (unsafeCoerce) toStrict :: TL.Tuple xs -> TS.Tuple xs toStrict U = U@@ -25,10 +22,6 @@ = let !y = x `seq` TS.Id x !ys = toStrict xs in y :* ys-#if __GLASGOW_HASKELL__ >= 802-#else-toStrict _ = error "Tuple.toStrict: impossible argument"-#endif fromStrict :: TS.Tuple xs -> TL.Tuple xs fromStrict = unsafeCoerce
src/Numeric/Tuple/Lazy.hs view
@@ -10,15 +10,13 @@ {-# LANGUAGE GADTs #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE IncoherentInstances #-}-{-# LANGUAGE KindSignatures #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE PolyKinds #-}-{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilyDependencies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-}@@ -29,9 +27,7 @@ -- Copyright : (c) Artem Chirkin -- License : BSD3 ----- Maintainer : chirkin@arch.ethz.ch ----- ----------------------------------------------------------------------------- module Numeric.Tuple.Lazy ( Id (..), Tuple@@ -40,56 +36,73 @@ ) where -import Control.Arrow (first)+import Control.Arrow (first) import Control.Monad.Fix import Control.Monad.Zip-import Data.Bits (Bits, FiniteBits)+import Data.Bits (Bits, FiniteBits) import Data.Coerce-import Data.Data (Data)+import Data.Data (Data) import Data.Foldable-import Data.Ix (Ix)-import Data.Monoid (Monoid (..))-import Data.Semigroup (Semigroup (..))-import Data.String (IsString)-import Foreign.Storable (Storable)-import GHC.Base (Type)+import Data.Functor.Classes+import Data.Ix (Ix)+import Data.Monoid as Mon (Monoid (..))+import Data.Semigroup as Sem (Semigroup (..))+import Data.String (IsString)+import Foreign.Storable (Storable)+import GHC.Base (Type) import GHC.Exts-import GHC.Generics (Generic, Generic1)-import qualified GHC.Read as Read-import qualified Text.Read as Read+import GHC.Generics (Generic, Generic1)+import qualified Text.Read as P -import Numeric.Type.List-import Numeric.TypedList+import Data.Type.List+import Numeric.TypedList -- | This is an almost complete copy of `Data.Functor.Identity` -- by (c) Andy Gill 2001. newtype Id a = Id { runId :: a } deriving ( Bits, Bounded, Data, Enum, Eq, FiniteBits, Floating, Fractional , Generic, Generic1, Integral, IsString, Ix, Monoid, Num, Ord- , Real, RealFrac, RealFloat , Semigroup, Storable, Traversable)+ , Real, RealFrac, RealFloat, Semigroup, Storable, Traversable) -instance (Read a) => Read (Id a) where+instance Read a => Read (Id a) where readsPrec d = fmap (first Id) . readsPrec d -instance (Show a) => Show (Id a) where+instance Show a => Show (Id a) where showsPrec d = showsPrec d . runId +instance Read1 Id where+ liftReadPrec r _ = coerce r+ liftReadListPrec = liftReadListPrecDefault+ liftReadList = liftReadListDefault++instance Show1 Id where+ liftShowsPrec f _ = coerce f++instance Eq1 Id where+ liftEq = coerce++instance Ord1 Id where+ liftCompare = coerce+ instance Foldable Id where foldMap = coerce- elem = (. runId) #. (==)+ elem = k (==)+ where+ k :: (a -> a -> Bool) -> a -> Id a -> Bool+ k = coerce foldl = coerce foldl' = coerce- foldl1 _ = runId+ foldl1 _ = coerce foldr f z (Id x) = f x z foldr' = foldr- foldr1 _ = runId+ foldr1 _ = coerce length _ = 1- maximum = runId- minimum = runId+ maximum = coerce+ minimum = coerce null _ = False- product = runId- sum = runId+ product = coerce+ sum = coerce toList (Id x) = [x] instance Functor Id where@@ -115,15 +128,10 @@ -- | A tuple indexed by a list of types type Tuple (xs :: [Type]) = TypedList Id xs ---- Starting from GHC 8.2, compiler supports specifying lists of complete--- pattern synonyms.-#if __GLASGOW_HASKELL__ >= 802 {-# COMPLETE U, (:$) #-} {-# COMPLETE U, (:!) #-} {-# COMPLETE Empty, (:$) #-} {-# COMPLETE Empty, (:!) #-}-#endif -- | Constructing a type-indexed list@@ -179,41 +187,21 @@ infixl 5 !* -instance (All Semigroup xs) => Semigroup (Tuple xs) where+instance All Semigroup xs => Sem.Semigroup (Tuple xs) where U <> U = U- (x :$ xs) <> (y :$ ys)- = (x <> y) *$ ( xs <> ys)-#if __GLASGOW_HASKELL__ >= 802-#else- _ <> _ = error "(<>): impossible combination of arguments"-#endif+ (x :$ xs) <> (y :$ ys) = (x <> y) *$ ( xs <> ys) -instance ( Semigroup (Tuple xs)- , RepresentableList xs- , All Monoid xs) => Monoid (Tuple xs) where+instance ( RepresentableList xs+ , All Semigroup xs+ , All Monoid xs) => Mon.Monoid (Tuple xs) where mempty = go (tList @Type @xs) where go :: forall (ys :: [Type]) . All Monoid ys => TypeList ys -> Tuple ys go U = U go (_ :* xs) = mempty *$ go xs-#if __GLASGOW_HASKELL__ >= 802-#else- go _ = error "mempty/go: impossible combination of arguments"-#endif- mappend = go (tList @Type @xs)- where- go :: forall (ys :: [Type])- . All Monoid ys- => TypeList ys- -> Tuple ys- -> Tuple ys- -> Tuple ys- go U _ _ = U- go (_ :* ts) (x :$ xs) (y :$ ys) = mappend x y *$ go ts xs ys-#if __GLASGOW_HASKELL__ >= 802-#else- go _ _ _ = error "mappend/go: impossible combination of arguments"+#if !(MIN_VERSION_base(4,11,0))+ mappend = (<>) #endif @@ -224,97 +212,36 @@ . All Bounded ys => TypeList ys -> Tuple ys go U = U go (_ :* xs) = minBound *$ go xs-#if __GLASGOW_HASKELL__ >= 802-#else- go _ = error "minBound/go: impossible combination of arguments"-#endif maxBound = go (tList @Type @xs) where go :: forall (ys :: [Type]) . All Bounded ys => TypeList ys -> Tuple ys go U = U go (_ :* xs) = maxBound *$ go xs-#if __GLASGOW_HASKELL__ >= 802-#else- go _ = error "maxBound/go: impossible combination of arguments"-#endif instance All Eq xs => Eq (Tuple xs) where (==) U U = True- (==) (x :* tx) (y :* ty) = x == y && tx == ty-#if __GLASGOW_HASKELL__ >= 802-#else- (==) _ _ = error "(==): impossible combination of arguments"-#endif+ (==) (x :* tx) (y :* ty) = eq1 x y && tx == ty (/=) U U = False- (/=) (x :* tx) (y :* ty) = x /= y || tx /= ty-#if __GLASGOW_HASKELL__ >= 802-#else- (/=) _ _ = error "(/=): impossible combination of arguments"-#endif+ (/=) (x :* tx) (y :* ty) = not (eq1 x y) || tx /= ty --- | Ord instance of the Tuple implements inverse lexicorgaphic ordering.--- That is, the last element in the tuple is the most significant one.------ Note, this will never work on infinite-dimensional tuples!+-- | Lexicorgaphic ordering; same as normal Haskell lists. instance (All Eq xs, All Ord xs) => Ord (Tuple xs) where compare U U = EQ- compare (x :* tx) (y :* ty) = compare tx ty <> compare x y-#if __GLASGOW_HASKELL__ >= 802-#else- compare _ _ = error "compare: impossible combination of arguments"-#endif+ compare (x :* tx) (y :* ty) = compare1 x y <> compare tx ty instance All Show xs => Show (Tuple xs) where- show U = "U"- show (x :* xs) = show x ++ " :* " ++ show xs-#if __GLASGOW_HASKELL__ >= 802-#else- show _ = error "show: impossible combination of arguments"-#endif- showsPrec _ U = showString "U"- showsPrec p (x :* xs) = showParen (p >= 5)- $ showsPrec 5 x- . showString " :* "- . showsPrec 5 xs-#if __GLASGOW_HASKELL__ >= 802-#else- showsPrec _ _ = error "showsPrec: impossible combination of arguments"-#endif--instance (RepresentableList xs, All Read xs) => Read (Tuple xs) where- readPrec = go (tList @Type @xs)- where- go :: forall (ys :: [Type])- . All Read ys => TypeList ys -> Read.ReadPrec (Tuple ys)- go U = U <$ Read.expectP (Read.Symbol "U")- go (_ :* ts) = Read.parens $ Read.prec 5 $ do- x <- Read.step Read.readPrec- Read.expectP (Read.Symbol ":*")- xs <- Read.step $ go ts- return (x :* xs)-#if __GLASGOW_HASKELL__ >= 802-#else- go _ = error "readPrec/go: impossible combination of arguments"-#endif-+ showsPrec = typedListShowsPrecC @Type @Show ":$" showsPrec1 +instance (All Read xs, RepresentableList xs) => Read (Tuple xs) where+ readPrec = typedListReadPrec @Type @Read ":$" readPrec1 (tList @Type @xs)+ readList = P.readListDefault+ readListPrec = P.readListPrecDefault -------------------------------------------------------------------------------- -- internal -------------------------------------------------------------------------------- ---- | Internal (non-exported) 'Coercible' helper for 'elem'------ See Note [Function coercion] in "Data.Foldable" for more details.-(#.) :: Coercible b c => (b -> c) -> (a -> b) -> a -> c-(#.) _f = coerce- forceCons :: Tuple xs -> Tuple xs-forceCons U = U+forceCons U = U forceCons (Id x :* xs) = x `seq` xs `seq` (Id x :* xs)-#if __GLASGOW_HASKELL__ >= 802-#else-forceCons _ = error "forceCons: impossible combination of arguments"-#endif
src/Numeric/Tuple/Strict.hs view
@@ -10,15 +10,13 @@ {-# LANGUAGE GADTs #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE IncoherentInstances #-}-{-# LANGUAGE KindSignatures #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE PolyKinds #-}-{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilyDependencies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-}@@ -29,9 +27,7 @@ -- Copyright : (c) Artem Chirkin -- License : BSD3 ----- Maintainer : chirkin@arch.ethz.ch ----- ----------------------------------------------------------------------------- module Numeric.Tuple.Strict ( Id (..), Tuple@@ -40,63 +36,80 @@ ) where -import Control.Arrow (first)+import Control.Arrow (first) import Control.Monad.Fix import Control.Monad.Zip-import Data.Bits (Bits, FiniteBits)+import Data.Bits (Bits, FiniteBits) import Data.Coerce-import Data.Data (Data)+import Data.Data (Data) import Data.Foldable-import Data.Ix (Ix)-import Data.Monoid (Monoid (..))-import Data.Semigroup (Semigroup (..))-import Data.String (IsString)-import Foreign.Storable (Storable)-import GHC.Base (Type)+import Data.Functor.Classes+import Data.Ix (Ix)+import Data.Monoid as Mon (Monoid (..))+import Data.Semigroup as Sem (Semigroup (..))+import Data.String (IsString)+import Foreign.Storable (Storable)+import GHC.Base (Type) import GHC.Exts-import GHC.Generics (Generic, Generic1)-import qualified GHC.Read as Read-import qualified Text.Read as Read+import GHC.Generics (Generic, Generic1)+import qualified Text.Read as P -import Numeric.Type.List-import Numeric.TypedList+import Data.Type.List+import Numeric.TypedList -- | This is an almost complete copy of `Data.Functor.Identity` -- by (c) Andy Gill 2001. newtype Id a = Id { runId :: a } deriving ( Bits, Bounded, Data, Enum, Eq, FiniteBits, Floating, Fractional , Generic, Generic1, Integral, IsString, Ix, Monoid, Num, Ord- , Real, RealFrac, RealFloat , Semigroup, Storable, Traversable)+ , Real, RealFrac, RealFloat, Semigroup, Storable, Traversable) -instance (Read a) => Read (Id a) where+instance Read a => Read (Id a) where readsPrec d = fmap (first Id) . readsPrec d -instance (Show a) => Show (Id a) where+instance Show a => Show (Id a) where showsPrec d = showsPrec d . runId +instance Read1 Id where+ liftReadPrec r _ = coerce r+ liftReadListPrec = liftReadListPrecDefault+ liftReadList = liftReadListDefault++instance Show1 Id where+ liftShowsPrec f _ = coerce f++instance Eq1 Id where+ liftEq = coerce++instance Ord1 Id where+ liftCompare = coerce+ instance Foldable Id where foldMap = coerce- elem = (. runId) #. (==)+ elem = k (==)+ where+ k :: (a -> a -> Bool) -> a -> Id a -> Bool+ k = coerce foldl = coerce foldl' = coerce- foldl1 _ = runId+ foldl1 _ = coerce foldr f z (Id x) = f x z foldr' = foldr- foldr1 _ = runId+ foldr1 _ = coerce length _ = 1- maximum = runId- minimum = runId+ maximum = coerce+ minimum = coerce null _ = False- product = runId- sum = runId+ product = coerce+ sum = coerce toList (Id x) = [x] instance Functor Id where fmap = coerce instance Applicative Id where- pure = Id+ pure = coerce (<*>) = coerce instance Monad Id where@@ -115,15 +128,10 @@ -- | A tuple indexed by a list of types type Tuple (xs :: [Type]) = TypedList Id xs ---- Starting from GHC 8.2, compiler supports specifying lists of complete--- pattern synonyms.-#if __GLASGOW_HASKELL__ >= 802 {-# COMPLETE U, (:$) #-} {-# COMPLETE U, (:!) #-} {-# COMPLETE Empty, (:$) #-} {-# COMPLETE Empty, (:!) #-}-#endif -- | Constructing a type-indexed list@@ -179,41 +187,21 @@ infixl 5 !* -instance (All Semigroup xs) => Semigroup (Tuple xs) where+instance All Semigroup xs => Sem.Semigroup (Tuple xs) where U <> U = U- (x :! xs) <> (y :! ys)- = (x <> y) *! ( xs <> ys)-#if __GLASGOW_HASKELL__ >= 802-#else- _ <> _ = error "(<>): impossible combination of arguments"-#endif+ (x :! xs) <> (y :! ys) = (x <> y) *! ( xs <> ys) -instance ( Semigroup (Tuple xs)- , RepresentableList xs- , All Monoid xs) => Monoid (Tuple xs) where+instance ( RepresentableList xs+ , All Semigroup xs+ , All Monoid xs) => Mon.Monoid (Tuple xs) where mempty = go (tList @Type @xs) where go :: forall (ys :: [Type]) . All Monoid ys => TypeList ys -> Tuple ys go U = U go (_ :* xs) = mempty *! go xs-#if __GLASGOW_HASKELL__ >= 802-#else- go _ = error "mempty/go: impossible combination of arguments"-#endif- mappend = go (tList @Type @xs)- where- go :: forall (ys :: [Type])- . All Monoid ys- => TypeList ys- -> Tuple ys- -> Tuple ys- -> Tuple ys- go U _ _ = U- go (_ :* ts) (x :! xs) (y :! ys) = mappend x y *! go ts xs ys-#if __GLASGOW_HASKELL__ >= 802-#else- go _ _ _ = error "mappend/go: impossible combination of arguments"+#if !(MIN_VERSION_base(4,11,0))+ mappend = (<>) #endif @@ -224,97 +212,36 @@ . All Bounded ys => TypeList ys -> Tuple ys go U = U go (_ :* xs) = minBound *! go xs-#if __GLASGOW_HASKELL__ >= 802-#else- go _ = error "minBound/go: impossible combination of arguments"-#endif maxBound = go (tList @Type @xs) where go :: forall (ys :: [Type]) . All Bounded ys => TypeList ys -> Tuple ys go U = U go (_ :* xs) = maxBound *! go xs-#if __GLASGOW_HASKELL__ >= 802-#else- go _ = error "maxBound/go: impossible combination of arguments"-#endif instance All Eq xs => Eq (Tuple xs) where (==) U U = True- (==) (x :* tx) (y :* ty) = x == y && tx == ty-#if __GLASGOW_HASKELL__ >= 802-#else- (==) _ _ = error "(==): impossible combination of arguments"-#endif+ (==) (x :* tx) (y :* ty) = eq1 x y && tx == ty (/=) U U = False- (/=) (x :* tx) (y :* ty) = x /= y || tx /= ty-#if __GLASGOW_HASKELL__ >= 802-#else- (/=) _ _ = error "(/=): impossible combination of arguments"-#endif+ (/=) (x :* tx) (y :* ty) = not (eq1 x y) || tx /= ty --- | Ord instance of the Tuple implements inverse lexicorgaphic ordering.--- That is, the last element in the tuple is the most significant one.------ Note, this will never work on infinite-dimensional tuples!+-- | Lexicorgaphic ordering; same as normal Haskell lists. instance (All Eq xs, All Ord xs) => Ord (Tuple xs) where compare U U = EQ- compare (x :* tx) (y :* ty) = compare tx ty <> compare x y-#if __GLASGOW_HASKELL__ >= 802-#else- compare _ _ = error "compare: impossible combination of arguments"-#endif+ compare (x :* tx) (y :* ty) = compare1 x y <> compare tx ty instance All Show xs => Show (Tuple xs) where- show U = "U"- show (x :* xs) = show x ++ " :* " ++ show xs-#if __GLASGOW_HASKELL__ >= 802-#else- show _ = error "show: impossible combination of arguments"-#endif- showsPrec _ U = showString "U"- showsPrec p (x :* xs) = showParen (p >= 5)- $ showsPrec 5 x- . showString " :* "- . showsPrec 5 xs-#if __GLASGOW_HASKELL__ >= 802-#else- showsPrec _ _ = error "showsPrec: impossible combination of arguments"-#endif--instance (RepresentableList xs, All Read xs) => Read (Tuple xs) where- readPrec = go (tList @Type @xs)- where- go :: forall (ys :: [Type])- . All Read ys => TypeList ys -> Read.ReadPrec (Tuple ys)- go U = U <$ Read.expectP (Read.Symbol "U")- go (_ :* ts) = Read.parens $ Read.prec 5 $ do- x <- Read.step Read.readPrec- Read.expectP (Read.Symbol ":*")- xs <- Read.step $ go ts- return (x :* xs)-#if __GLASGOW_HASKELL__ >= 802-#else- go _ = error "readPrec/go: impossible combination of arguments"-#endif-+ showsPrec = typedListShowsPrecC @Type @Show ":!" showsPrec1 +instance (All Read xs, RepresentableList xs) => Read (Tuple xs) where+ readPrec = typedListReadPrec @Type @Read ":!" readPrec1 (tList @Type @xs)+ readList = P.readListDefault+ readListPrec = P.readListPrecDefault -------------------------------------------------------------------------------- -- internal -------------------------------------------------------------------------------- ---- | Internal (non-exported) 'Coercible' helper for 'elem'------ See Note [Function coercion] in "Data.Foldable" for more details.-(#.) :: Coercible b c => (b -> c) -> (a -> b) -> a -> c-(#.) _f = coerce- forceCons :: Tuple xs -> Tuple xs-forceCons U = U+forceCons U = U forceCons (Id x :* xs) = x `seq` xs `seq` (Id x :* xs)-#if __GLASGOW_HASKELL__ >= 802-#else-forceCons _ = error "forceCons: impossible combination of arguments"-#endif
− src/Numeric/Type/Evidence.hs
@@ -1,59 +0,0 @@-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE PolyKinds #-}--------------------------------------------------------------------------------- |--- Module : Numeric.Type.Evidence--- Copyright : (c) Artem Chirkin--- License : BSD3------ Maintainer : chirkin@arch.ethz.ch------ Construct type-level evidence at runtime----------------------------------------------------------------------------------module Numeric.Type.Evidence- ( Evidence (..), withEvidence, sumEvs, (+!+)- , Evidence' (..), toEvidence, toEvidence'- ) where---import GHC.Base (Type)-import GHC.Exts (Constraint)----- | Bring an instance of certain class or constaint satisfaction evidence into scope.-data Evidence :: Constraint -> Type where- E :: a => Evidence a---- | Combine evidence-sumEvs :: Evidence a -> Evidence b -> Evidence (a,b)-sumEvs E E = E-{-# INLINE sumEvs #-}--infixl 4 +!+--- | Combine evidence-(+!+) :: Evidence a -> Evidence b -> Evidence (a,b)-(+!+) = sumEvs-{-# INLINE (+!+) #-}---- | Pattern match agains evidence to get constraints info-withEvidence :: Evidence a -> (a => r) -> r-withEvidence d r = case d of E -> r-{-# INLINE withEvidence #-}---- | Same as @Evidence@, but allows to separate constraint function from--- the type it is applied to.-data Evidence' :: (k -> Constraint) -> k -> Type where- E' :: c a => Evidence' c a--toEvidence :: Evidence' c a -> Evidence (c a)-toEvidence E' = E-{-# INLINE toEvidence #-}--toEvidence' :: Evidence (c a) -> Evidence' c a-toEvidence' E = E'-{-# INLINE toEvidence' #-}
− src/Numeric/Type/List.hs
@@ -1,222 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE ExplicitNamespaces #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeFamilyDependencies #-}-{-# LANGUAGE TypeInType #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}------------------------------------------------------------------------------------ |--- Module : Numeric.Type.List--- Copyright : (c) Artem Chirkin--- License : BSD3------ Maintainer : chirkin@arch.ethz.ch------ Provides type-level operations on lists.-----------------------------------------------------------------------------------------module Numeric.Type.List- ( -- * Basic operations- type (++), type (+:), type (:+)- , Empty, Cons, Snoc, Head- , Tail, Init, Last, Concat, Reverse, Take, Drop, Length- , All, Map- -- * Working with concatenations- , Suffix, Prefix, IsPrefix, IsSuffix- -- * Term level functions- , ConcatList- ) where--import GHC.Exts-import GHC.TypeLits----- | Synonym for a type-level cons--- (injective, since this is just a synonym for the list constructor)-type (a :: k) :+ (as :: [k]) = a ': as-infixr 5 :+--- | Prefix-style synonym for cons-type Cons (n :: k) (ns :: [k]) = n :+ ns---- | Synonym for a type-level snoc (injective!)-type (ns :: [k]) +: (n :: k) = Snoc ns n-infixl 5 +:--- | Prefix-style synonym for snoc-type Snoc (ns :: [k]) (n :: k) = GetSnoc k (DoSnoc k ns n)----- | List concatenation-type family (as :: [k]) ++ (bs :: [k]) :: [k] where- (++) '[] bs = bs- (++) as '[] = as- (++) (a :+ as) bs = a :+ (as ++ bs)-infixr 5 ++---- | Prefix-style synonym for concatenation-type Concat (as :: [k]) (bs :: [k]) = as ++ bs----- | Reverse a type-level list (injective!)-type Reverse (xs :: [k]) = Reversed k (DoReverse k xs)----- | Synonym for an empty type-level list-type Empty = '[]---type family Take (n::Nat) (xs :: [k]) :: [k] where- Take _ '[] = '[]- Take 0 xs = '[]- Take n (x :+ xs) = x :+ Take (n-1) xs---type family Drop (n::Nat) (xs :: [k]) :: [k] where- Drop _ '[] = '[]- Drop 0 xs = xs- Drop n (x :+ xs) = Drop (n-1) xs--type family Suffix (as :: [k]) (asbs :: [k]) :: [k] where- Suffix '[] bs = bs- Suffix as as = '[]- Suffix (_ :+ as) (_ :+ asbs) = Suffix as asbs--type family Prefix (bs :: [k]) (asbs :: [k]) :: [k] where- Prefix '[] as = as- Prefix bs bs = '[]- Prefix bs asbs = Take (Length asbs - Length bs) asbs---type family IsPrefix (as :: [k]) (asbs :: [k]) :: Bool where- IsPrefix '[] _ = 'True- IsPrefix (a :+ as) (a :+ asbs) = IsPrefix as asbs- IsPrefix as as = 'True- IsPrefix _ _= 'False--type family IsSuffix (as :: [k]) (asbs :: [k]) :: Bool where- IsSuffix '[] _ = 'True- IsSuffix bs bs = 'True- IsSuffix bs (_ :+ sbs) = IsSuffix bs sbs- IsSuffix _ _ = 'False---type family Head (xs :: [k]) :: k where- Head (x :+ xs) = x- Head (KEmpty k) = TypeError ( 'Text- "Head: empty type-level list."- ':$$: FamErrMsg k- )--type family Tail (xs :: [k]) :: [k] where- Tail (x :+ xs) = xs- Tail (KEmpty k) = TypeError ( 'Text- "Tail: empty type-level list."- ':$$: FamErrMsg k- )--type family Init (xs :: [k]) :: [k] where- Init '[x] = '[]- Init (x :+ xs) = x :+ Init xs- Init (KEmpty k) = TypeError ( 'Text- "Init: empty type-level list."- ':$$: FamErrMsg k- )--type family Last (xs :: [k]) :: k where- Last '[x] = x- Last (x :+ xs) = Last xs- Last (KEmpty k) = TypeError ( 'Text- "Last: empty type-level list."- ':$$: FamErrMsg k- )--type family Length (xs :: [k]) :: Nat where- Length '[] = 0- Length (_ ': xs) = 1 + Length xs---type family All (f :: k -> Constraint) (xs :: [k]) :: Constraint where- All _ '[] = ()- All f (x ': xs) = (f x, All f xs)--type family Map (f :: a -> b) (xs :: [a]) :: [b] where- Map f '[] = '[]- Map f (x ': xs) = f x ': Map f xs----- | Represent a triple of lists forming a relation `as ++ bs ~ asbs`-class ( asbs ~ Concat as bs- , as ~ Prefix bs asbs- , bs ~ Suffix as asbs- , IsSuffix bs asbs ~ 'True- , IsPrefix as asbs ~ 'True- ) => ConcatList (as :: [k]) (bs :: [k]) (asbs :: [k])- | as bs -> asbs- , as asbs -> bs- , bs asbs -> as--instance ( asbs ~ Concat as bs- , as ~ Prefix bs asbs- , bs ~ Suffix as asbs- , IsSuffix bs asbs ~ 'True- , IsPrefix as asbs ~ 'True- ) => ConcatList (as :: [k]) (bs :: [k]) (asbs :: [k])----type FamErrMsg k- = 'Text "Type-level error occured when operating on a list of kind "- ':<>: 'ShowType [k] ':<>: 'Text "."--------------------------------------------------------------------------------------- Tricks to make some type-level operations injective--------------------------------------------------------------------------------------- | A special data type that can have either a single element,--- or more than two.--- This feature is not enforced in the type system - this is just a way to make injective Snoc.-data Snocing k = SSingle k | SCons [k]-type SSingle k x = 'SSingle (x :: k)-type SCons k xs = 'SCons (xs :: [k])-type KCons k x xs = (x :: k) ': (xs :: [k])-type KEmpty k = ('[] :: [k])-type KSingle k x = ('[x] :: [k])--type family DoSnoc k (xs :: [k]) (z::k) = (ys :: Snocing k) | ys -> xs z where- DoSnoc k '[] x = SSingle k x- DoSnoc k (KCons k x xs) y =- (SCons k (KCons k x (GetSnoc k (DoSnoc k xs y)) :: [k]) :: Snocing k)---type family GetSnoc k (xs :: Snocing k) = (ys :: [k]) | ys -> xs where- GetSnoc k (SSingle k x) = KSingle k x- GetSnoc k (SCons k (KCons k y (KCons k x xs))) =- KCons k y (KCons k x xs)---- | Another data type to make Reverse injective.-data Reversing k = REmpty | RReverse [k]-type REmpty k = 'REmpty-type RReverse k xs = 'RReverse (xs :: [k])----type family Reversed k (ts :: Reversing k) = (rs :: [k]) | rs -> ts where- Reversed k (REmpty k) = KEmpty k- Reversed k (RReverse k (KCons k x xs)) = KCons k x xs---type family DoReverse k (as :: [k]) = (rs :: Reversing k) | rs -> as where- DoReverse k '[] = REmpty k- DoReverse k (KCons k a as) =- RReverse k (GetSnoc k (DoSnoc k (Reversed k (DoReverse k as)) a))
src/Numeric/TypedList.hs view
@@ -1,31 +1,31 @@-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE MagicHash #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeFamilyDependencies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilyDependencies #-}+{-# LANGUAGE TypeInType #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ViewPatterns #-} ----------------------------------------------------------------------------- -- | -- Module : Numeric.TypedList -- Copyright : (c) Artem Chirkin -- License : BSD3 ----- Maintainer : chirkin@arch.ethz.ch ----- -- Provide a type-indexed heterogeneous list type @TypedList@. -- Behind the facade, @TypedList@ is just a plain list of haskell pointers. -- It is used to represent dimension lists, indices, and just flexible tuples.@@ -37,7 +37,9 @@ module Numeric.TypedList ( TypedList (U, (:*), Empty, TypeList, EvList, Cons, Snoc, Reverse) , RepresentableList (..)- , TypeList, types, order, order'+ , Dict1 (..), DictList+ , TypeList, types, typeables,inferTypeableList+ , order, order' , cons, snoc , Numeric.TypedList.reverse , Numeric.TypedList.take@@ -47,29 +49,36 @@ , Numeric.TypedList.last , Numeric.TypedList.init , Numeric.TypedList.splitAt+ , Numeric.TypedList.stripPrefix+ , Numeric.TypedList.stripSuffix+ , Numeric.TypedList.sameList , Numeric.TypedList.concat , Numeric.TypedList.length , Numeric.TypedList.map- , module Numeric.Type.List+ , module Data.Type.List+ -- * Deriving Show and Read+ , typedListShowsPrecC, typedListShowsPrec+ , typedListReadPrec, withTypedListReadPrec ) where -import Control.Arrow (first)-import Data.Proxy-import GHC.Base (Type)+import Control.Arrow (first)+import Data.Constraint hiding ((***))+import Data.Data+import Data.Type.List+import Data.Void+import GHC.Base (Type) import GHC.Exts--import Numeric.Dim-import Numeric.Type.Evidence-import Numeric.Type.List+import GHC.Generics hiding (Infix, Prefix)+import qualified Text.ParserCombinators.ReadPrec as Read+import qualified Text.Read as Read+import qualified Text.Read.Lex as Read+import qualified Type.Reflection as R +import {-# SOURCE #-} Numeric.Dimensions.Dim (Dim, Nat, dimVal, minusDimM) -- | Type-indexed list newtype TypedList (f :: (k -> Type)) (xs :: [k]) = TypedList [Any]----- Starting from GHC 8.2, compiler supports specifying lists of complete--- pattern synonyms.-#if __GLASGOW_HASKELL__ >= 802+ deriving (Typeable) {-# COMPLETE TypeList #-} {-# COMPLETE EvList #-} {-# COMPLETE U, (:*) #-}@@ -79,48 +88,123 @@ {-# COMPLETE Empty, Cons #-} {-# COMPLETE Empty, Snoc #-} {-# COMPLETE Reverse #-}-#endif +-- | Term-level structure of a @TypedList f xs@ is fully determined by its+-- type @Typeable xs@.+-- Thus, @gunfold@ does not use its last argument (@Constr@) at all,+-- relying on the structure of the type parameter.+instance (Typeable k, Typeable f, Typeable xs, All Data (Map f xs))+ => Data (TypedList (f :: (k -> Type)) (xs :: [k])) where+ gfoldl _ z U = z U+ gfoldl k z (x :* xs) = case inferTypeableCons @_ @xs of+ Dict -> z (:*) `k` x `k` xs+ gunfold k z _ = case typeables @k @xs of+ U -> z U+ _ :* _ -> case inferTypeableCons @_ @xs of Dict -> k (k (z (:*)))+ toConstr U = typedListConstrEmpty+ toConstr (_ :* _) = typedListConstrCons+ dataTypeOf _ = typedListDataType++typedListDataType :: DataType+typedListDataType = mkDataType+ "Numeric.TypedList.TypedList" [typedListConstrEmpty, typedListConstrCons]++typedListConstrEmpty :: Constr+typedListConstrEmpty = mkConstr typedListDataType "U" [] Prefix++typedListConstrCons :: Constr+typedListConstrCons = mkConstr typedListDataType ":*" [] Infix+++type family TypedListRepNil (xs :: [k]) :: (Type -> Type) where+ TypedListRepNil '[] = C1 ('MetaCons "U" 'PrefixI 'False) U1+ TypedListRepNil (_ ': _) = Rec0 Void++type family TypedListRepCons (f :: (k -> Type)) (xs :: [k]) :: (Type -> Type) where+ TypedListRepCons _ '[] = Rec0 Void+ TypedListRepCons f (x ': xs) = C1 ('MetaCons ":*" ('InfixI 'RightAssociative 5) 'False)+ ( S1 ('MetaSel 'Nothing 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy)+ (Rec0 (f x))+ :*:+ S1 ('MetaSel 'Nothing 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy)+ (Rec0 (TypedList f xs))+ )++instance Generic (TypedList (f :: (k -> Type)) (xs :: [k])) where+ type Rep (TypedList f xs) = D1+ ('MetaData "TypedList" "Numeric.TypedList" "dimensions" 'False)+ ( TypedListRepNil xs :+: TypedListRepCons f xs )+ from U = M1 (L1 (M1 U1))+ from (x :* xs) = M1 (R1 (M1 (M1 (K1 x) :*: M1 (K1 xs))))+ to (M1 (L1 _))+ | Dict <- unsafeEqTypes @[k] @xs @'[] = U+ to (M1 (R1 xxs))+ | Dict <- unsafeEqTypes @[k] @xs @(Head xs ': Tail xs)+ , M1 (M1 (K1 x) :*: M1 (K1 xs)) <- xxs = x :* xs+ -- | A list of type proxies type TypeList (xs :: [k]) = TypedList Proxy xs +-- | Same as `Dict`, but allows to separate constraint function from+-- the type it is applied to.+data Dict1 :: (k -> Constraint) -> k -> Type where+ Dict1 :: c a => Dict1 c a+ deriving Typeable --- | A list of evidence for constraints-type EvidenceList (c :: k -> Constraint) (xs :: [k])- = TypedList (Evidence' c) xs+instance (Typeable k, Typeable p, Typeable a, p a)+ => Data (Dict1 (p :: k -> Constraint) (a :: k)) where+ gfoldl _ z Dict1 = z Dict1+ toConstr _ = dictConstr+ gunfold _ z _ = z Dict1+ dataTypeOf _ = dictDataType +dictConstr :: Constr+dictConstr = mkConstr dictDataType "Dict1" [] Prefix +dictDataType :: DataType+dictDataType = mkDataType "Numeric.TypedList.Dict1" [dictConstr]++deriving instance Eq (Dict1 (p :: k -> Constraint) (a :: k))+deriving instance Ord (Dict1 (p :: k -> Constraint) (a :: k))+deriving instance Show (Dict1 (p :: k -> Constraint) (a :: k))+++-- | A list of dicts for the same constraint over several types.+type DictList (c :: k -> Constraint) (xs :: [k])+ = TypedList (Dict1 c) xs++ -- | Pattern matching against this causes `RepresentableList` instance -- come into scope. -- Also it allows constructing a term-level list out of a constraint.-pattern TypeList :: forall (xs :: [k])+pattern TypeList :: forall (k :: Type) (xs :: [k]) . () => RepresentableList xs => TypeList xs-pattern TypeList <- (mkRTL -> E)+pattern TypeList <- (mkRTL -> Dict) where TypeList = tList @k @xs -- | Pattern matching against this allows manipulating lists of constraints. -- Useful when creating functions that change the shape of dimensions.-pattern EvList :: forall (c :: k -> Constraint) (xs :: [k])- . () => (All c xs, RepresentableList xs) => EvidenceList c xs-pattern EvList <- (mkEVL -> E)+pattern EvList :: forall (k :: Type) (c :: k -> Constraint) (xs :: [k])+ . () => (All c xs, RepresentableList xs) => DictList c xs+pattern EvList <- (mkEVL -> Dict) where EvList = _evList (tList @k @xs) -- | Zero-length type list-pattern U :: forall (f :: k -> Type) (xs :: [k])+pattern U :: forall (k :: Type) (f :: k -> Type) (xs :: [k]) . () => (xs ~ '[]) => TypedList f xs-pattern U <- (patTL @f @xs -> PatCNil)+pattern U <- (patTL @k @f @xs -> PatCNil) where- U = unsafeCoerce# []+ U = coerce ([] :: [Any]) -- | Zero-length type list; synonym to `U`.-pattern Empty :: forall (f :: k -> Type) (xs :: [k])+pattern Empty :: forall (k :: Type) (f :: k -> Type) (xs :: [k]) . () => (xs ~ '[]) => TypedList f xs pattern Empty = U -- | Constructing a type-indexed list-pattern (:*) :: forall (f :: k -> Type) (xs :: [k])+pattern (:*) :: forall (k :: Type) (f :: k -> Type) (xs :: [k]) . () => forall (y :: k) (ys :: [k]) . (xs ~ (y ': ys)) => f y -> TypedList f ys -> TypedList f xs@@ -128,90 +212,158 @@ infixr 5 :* -- | Constructing a type-indexed list in the canonical way-pattern Cons :: forall (f :: k -> Type) (xs :: [k])+pattern Cons :: forall (k :: Type) (f :: k -> Type) (xs :: [k]) . () => forall (y :: k) (ys :: [k]) . (xs ~ (y ': ys)) => f y -> TypedList f ys -> TypedList f xs-pattern Cons x xs <- (patTL @f @xs -> PatCons x xs)+pattern Cons x xs <- (patTL @k @f @xs -> PatCons x xs) where Cons = Numeric.TypedList.cons -- | Constructing a type-indexed list from the other end-pattern Snoc :: forall (f :: k -> Type) (xs :: [k])+pattern Snoc :: forall (k :: Type) (f :: k -> Type) (xs :: [k]) . () => forall (sy :: [k]) (y :: k) . (xs ~ (sy +: y)) => TypedList f sy -> f y -> TypedList f xs-pattern Snoc sx x <- (unsnocTL @f @xs -> PatSnoc sx x)+pattern Snoc sx x <- (unsnocTL @k @f @xs -> PatSnoc sx x) where Snoc = Numeric.TypedList.snoc -- | Reverse a typed list-pattern Reverse :: forall (f :: k -> Type) (xs :: [k])+pattern Reverse :: forall (k :: Type) (f :: k -> Type) (xs :: [k]) . () => forall (sx :: [k]) . (xs ~ Reverse sx, sx ~ Reverse xs) => TypedList f sx -> TypedList f xs-pattern Reverse sx <- (unreverseTL @f @xs -> PatReverse sx)+pattern Reverse sx <- (unreverseTL @k @f @xs -> PatReverse sx) where Reverse = Numeric.TypedList.reverse -cons :: f x -> TypedList f xs -> TypedList f (x :+ xs)-cons x xs = TypedList (unsafeCoerce# x : unsafeCoerce# xs)+cons :: forall (k :: Type) (f :: k -> Type) (x :: k) (xs :: [k])+ . f x -> TypedList f xs -> TypedList f (x :+ xs)+cons x xs = TypedList (unsafeCoerce# x : coerce xs) {-# INLINE cons #-} -snoc :: TypedList f xs -> f x -> TypedList f (xs +: x)-snoc xs x = TypedList (unsafeCoerce# xs ++ [unsafeCoerce# x])+snoc :: forall (k :: Type) (f :: k -> Type) (xs :: [k]) (x :: k)+ . TypedList f xs -> f x -> TypedList f (xs +: x)+snoc xs x = TypedList (coerce xs ++ [unsafeCoerce# x]) {-# INLINE snoc #-} -reverse :: TypedList f xs -> TypedList f (Reverse xs)-reverse (TypedList sx) = unsafeCoerce# (Prelude.reverse sx)+reverse :: forall (k :: Type) (f :: k -> Type) (xs :: [k])+ . TypedList f xs -> TypedList f (Reverse xs)+reverse = coerce (Prelude.reverse :: [Any] -> [Any]) {-# INLINE reverse #-} -take :: Dim n -> TypedList f xs -> TypedList f (Take n xs)-take d (TypedList xs) = unsafeCoerce# (Prelude.take (intD d) xs)-{-# INLINE take #-}--drop :: Dim n -> TypedList f xs -> TypedList f (Drop n xs)-drop d (TypedList xs) = unsafeCoerce# (Prelude.drop (intD d) xs)-{-# INLINE drop #-}--head :: TypedList f xs -> f (Head xs)+head :: forall (k :: Type) (f :: k -> Type) (xs :: [k])+ . TypedList f xs -> f (Head xs) head (TypedList xs) = unsafeCoerce# (Prelude.head xs) {-# INLINE head #-} -tail :: TypedList f xs -> TypedList f (Tail xs)-tail (TypedList xs) = unsafeCoerce# (Prelude.tail xs)+tail :: forall (k :: Type) (f :: k -> Type) (xs :: [k])+ . TypedList f xs -> TypedList f (Tail xs)+tail = coerce (Prelude.tail :: [Any] -> [Any]) {-# INLINE tail #-} -init :: TypedList f xs -> TypedList f (Init xs)-init (TypedList xs) = unsafeCoerce# (Prelude.init xs)+init :: forall (k :: Type) (f :: k -> Type) (xs :: [k])+ . TypedList f xs -> TypedList f (Init xs)+init = coerce (Prelude.init :: [Any] -> [Any]) {-# INLINE init #-} -last :: TypedList f xs -> f (Last xs)+last :: forall (k :: Type) (f :: k -> Type) (xs :: [k])+ . TypedList f xs -> f (Last xs) last (TypedList xs) = unsafeCoerce# (Prelude.last xs) {-# INLINE last #-} -length :: TypedList f xs -> Dim (Length xs)+take :: forall (k :: Type) (n :: Nat) (f :: k -> Type) (xs :: [k])+ . Dim n -> TypedList f xs -> TypedList f (Take n xs)+take = coerce (Prelude.take . dimValInt :: Dim n -> [Any] -> [Any])+{-# INLINE take #-}++drop :: forall (k :: Type) (n :: Nat) (f :: k -> Type) (xs :: [k])+ . Dim n -> TypedList f xs -> TypedList f (Drop n xs)+drop = coerce (Prelude.drop . dimValInt :: Dim n -> [Any] -> [Any])+{-# INLINE drop #-}++length :: forall (k :: Type) (f :: k -> Type) (xs :: [k])+ . TypedList f xs -> Dim (Length xs) length = order {-# INLINE length #-} -splitAt :: Dim n+splitAt :: forall (k :: Type) (n :: Nat) (f :: k -> Type) (xs :: [k])+ . Dim n -> TypedList f xs -> (TypedList f (Take n xs), TypedList f (Drop n xs))-splitAt d (TypedList xs) = unsafeCoerce# (Prelude.splitAt (intD d) xs)+splitAt = coerce (Prelude.splitAt . dimValInt :: Dim n -> [Any] -> ([Any], [Any])) {-# INLINE splitAt #-} -concat :: TypedList f xs+order' :: forall (k :: Type) (xs :: [k])+ . RepresentableList xs => Dim (Length xs)+order' = order (tList @_ @xs)+{-# INLINE order' #-}++order :: forall (k :: Type) (f :: k -> Type) (xs :: [k])+ . TypedList f xs -> Dim (Length xs)+order = unsafeCoerce# (fromIntegral . Prelude.length :: [Any] -> Word)+{-# INLINE order #-}++concat :: forall (k :: Type) (f :: k -> Type) (xs :: [k]) (ys :: [k])+ . TypedList f xs -> TypedList f ys -> TypedList f (xs ++ ys)-concat (TypedList xs) (TypedList ys) = unsafeCoerce# (xs ++ ys)+concat = coerce ((++) :: [Any] -> [Any] -> [Any]) {-# INLINE concat #-} +stripPrefix :: forall (k :: Type) (f :: k -> Type) (xs :: [k]) (ys :: [k])+ . ( All Typeable xs, All Typeable ys, All Eq (Map f xs))+ => TypedList f xs+ -> TypedList f ys+ -> Maybe (TypedList f (StripPrefix xs ys))+stripPrefix U ys = Just ys+stripPrefix _ U = Nothing+stripPrefix ((x :: f x) :* xs) ((y :: f y) :* ys)+ | Just Refl <- eqT @x @y+ , x == y = coerce (stripPrefix xs ys)+ | otherwise = Nothing+{-# INLINE stripPrefix #-}++stripSuffix :: forall (k :: Type) (f :: k -> Type) (xs :: [k]) (ys :: [k])+ . ( All Typeable xs, All Typeable ys, All Eq (Map f xs))+ => TypedList f xs+ -> TypedList f ys+ -> Maybe (TypedList f (StripSuffix xs ys))+stripSuffix U ys = Just ys+stripSuffix _ U = Nothing+stripSuffix xs ys+ | Just n <- order ys `minusDimM` order xs+ , (zs, xs') <- Numeric.TypedList.splitAt n ys+ , EvList <- Numeric.TypedList.drop n $ _evList @_ @Typeable ys+ , Just (Refl, True) <- sameList xs xs'+ = Just (coerce zs)+ | otherwise = Nothing+{-# INLINE stripSuffix #-}++-- | Returns two things at once:+-- (Evidence that types of lists match, value-level equality).+sameList :: forall (k :: Type) (f :: k -> Type) (xs :: [k]) (ys :: [k])+ . ( All Typeable xs, All Typeable ys, All Eq (Map f xs))+ => TypedList f xs+ -> TypedList f ys+ -> Maybe (xs :~: ys, Bool)+sameList U U = Just (Refl, True)+sameList ((x :: f x) :* xs) ((y :: f y) :* ys)+ | Just Refl <- eqT @x @y+ , Just (Refl, b) <- sameList xs ys+ = Just (Refl, x == y && b)+ | otherwise+ = Nothing+sameList _ _ = Nothing+ -- | Map a function over contents of a typed list-map :: (forall a . f a -> g a)+map :: forall (k :: Type) (f :: k -> Type) (g :: k -> Type) (xs :: [k])+ . (forall (a :: k) . f a -> g a) -> TypedList f xs -> TypedList g xs-map k (TypedList xs) = unsafeCoerce# (Prelude.map k' xs)+map k = coerce (Prelude.map k') where k' :: Any -> Any k' = unsafeCoerce# . k . unsafeCoerce#@@ -223,10 +375,37 @@ -- -- > case types ts of TypeList -> ... ---types :: TypedList f xs -> TypeList xs+types :: forall (k :: Type) (f :: k -> Type) (xs :: [k])+ . TypedList f xs -> TypeList xs types (TypedList xs) = unsafeCoerce# (Prelude.map (const Proxy) xs) {-# INLINE types #-} +-- | Construct a @TypeList xs@ if there is an instance of @Typeable xs@ around.+--+-- This way, you can always bring `RepresentableList` instance into the scope+-- if you have a `Typeable` instance.+--+typeables :: forall (k :: Type) (xs :: [k]) . Typeable xs => TypeList xs+typeables = case R.typeRep @xs of+ R.App (R.App _ (_ :: R.TypeRep (n :: k1))) (txs :: R.TypeRep (ns :: k2))+ -> case (unsafeCoerce# (Dict @(k1 ~ k1, k2 ~ k2))+ :: Dict (k ~ k1, [k] ~ k2)) of+ Dict -> case (unsafeCoerce# (Dict @(xs ~ xs))+ :: Dict (xs ~ (n ': ns))) of+ Dict -> Proxy @n :* R.withTypeable txs (typeables @k @ns)+ R.Con _+ -> unsafeCoerce# U+ r -> error ("typeables -- impossible typeRep: " ++ show r)+{-# INLINE typeables #-}++-- | If all elements of a @TypedList@ are @Typeable@,+-- then the list of these elements is also @Typeable@.+inferTypeableList :: forall (k :: Type) (f :: k -> Type) (xs :: [k])+ . (Typeable k, All Typeable xs)+ => TypedList f xs -> Dict (Typeable xs)+inferTypeableList U = Dict+inferTypeableList (_ :* xs) = case inferTypeableList xs of Dict -> Dict+ -- | Representable type lists. -- Allows getting type information about list structure at runtime. class RepresentableList (xs :: [k]) where@@ -239,17 +418,68 @@ instance RepresentableList xs => RepresentableList (x ': xs :: [k]) where tList = Proxy @x :* tList @k @xs --order' :: forall xs . RepresentableList xs => Dim (Length xs)-order' = order (tList @_ @xs)-{-# INLINE order' #-}+-- | Generic show function for a @TypedList@.+typedListShowsPrecC :: forall (k :: Type) (c :: k -> Constraint) (f :: k -> Type) (xs :: [k])+ . All c xs+ => String+ -- ^ Override cons symbol+ -> ( forall (x :: k) . c x => Int -> f x -> ShowS )+ -- ^ How to show a single element+ -> Int -> TypedList f xs -> ShowS+typedListShowsPrecC _ _ _ U = showChar 'U'+typedListShowsPrecC consS elShowsPrec p (x :* xs) = showParen (p >= 6)+ $ elShowsPrec 6 x+ . showChar ' ' . showString consS . showChar ' '+ . typedListShowsPrecC @k @c @f consS elShowsPrec 5 xs -order :: TypedList f xs -> Dim (Length xs)-order (TypedList xs) = unsafeCoerce# (fromIntegral (Prelude.length xs) :: Word)-{-# INLINE order #-}+-- | Generic show function for a @TypedList@.+typedListShowsPrec :: forall (k :: Type) (f :: k -> Type) (xs :: [k])+ . ( forall (x :: k) . Int -> f x -> ShowS )+ -- ^ How to show a single element+ -> Int -> TypedList f xs -> ShowS+typedListShowsPrec _ _ U = showChar 'U'+typedListShowsPrec elShowsPrec p (x :* xs) = showParen (p >= 6) $+ elShowsPrec 6 x . showString " :* " . typedListShowsPrec @k @f elShowsPrec 5 xs +-- | Generic read function for a @TypedList@.+-- Requires a "template" to enforce the structure of the type list.+typedListReadPrec :: forall (k :: Type) (c :: k -> Constraint) (f :: k -> Type)+ (xs :: [k]) (g :: k -> Type)+ . All c xs+ => String+ -- ^ Override cons symbol+ -> ( forall (x :: k) . c x => Read.ReadPrec (f x) )+ -- ^ How to read a single element+ -> TypedList g xs+ -- ^ Enforce the type structure of the result+ -> Read.ReadPrec (TypedList f xs)+typedListReadPrec _ _ U = Read.parens $ U <$ Read.lift (Read.expect $ Read.Ident "U")+typedListReadPrec consS elReadPrec (_ :* ts) = Read.parens . Read.prec 5 $ do+ x <- Read.step elReadPrec+ Read.lift . Read.expect $ Read.Symbol consS+ xs <- typedListReadPrec @k @c consS elReadPrec ts+ return (x :* xs) +-- | Generic read function for a @TypedList@ of unknown length.+withTypedListReadPrec :: forall (k :: Type) (f :: k -> Type) (r :: Type)+ . (forall (z :: Type) .+ ( forall (x :: k) . f x -> z) -> Read.ReadPrec z )+ -- ^ How to read a single element+ -> (forall (xs :: [k]) . TypedList f xs -> r )+ -- ^ Consume the result+ -> Read.ReadPrec r+withTypedListReadPrec withElReadPrec use = Read.parens $+ (use U <$ Read.lift (Read.expect $ Read.Ident "U"))+ Read.++++ Read.prec 5 (do+ WithAnyTL withX <- Read.step $ withElReadPrec (\x -> WithAnyTL $ use . (x :*))+ Read.lift . Read.expect $ Read.Symbol ":*"+ withTypedListReadPrec @k @f @r withElReadPrec withX+ ) +-- Workaround impredicative polymorphism+newtype WithAnyTL (f :: k -> Type) (r :: Type)+ = WithAnyTL (forall (xs :: [k]) . TypedList f xs -> r) -------------------------------------------------------------------------------- -- internal@@ -260,7 +490,7 @@ -- to create an instance of `RepresentableList` typeclass at runtime. -- The trick is taken from Edward Kmett's reflection library explained -- in https://www.schoolofhaskell.com/user/thoughtpolice/using-reflection-reifyRepList :: forall xs r+reifyRepList :: forall (k :: Type) (xs :: [k]) (r :: Type) . TypeList xs -> (RepresentableList xs => r) -> r@@ -268,76 +498,74 @@ {-# INLINE reifyRepList #-} newtype MagicRepList xs r = MagicRepList (RepresentableList xs => r) -data PatReverse f xs+data PatReverse (f :: k -> Type) (xs :: [k]) = forall (sx :: [k]) . (xs ~ Reverse sx, sx ~ Reverse xs) => PatReverse (TypedList f sx) -unreverseTL :: forall f xs . TypedList f xs -> PatReverse f xs+unreverseTL :: forall (k :: Type) (f :: k -> Type) (xs :: [k])+ . TypedList f xs -> PatReverse f xs unreverseTL (TypedList xs)- = case (unsafeCoerce# (E @(xs ~ xs, xs ~ xs))- :: Evidence (xs ~ Reverse sx, sx ~ Reverse xs)+ = case (unsafeCoerce# (Dict @(xs ~ xs, xs ~ xs))+ :: Dict (xs ~ Reverse sx, sx ~ Reverse xs) ) of- E -> PatReverse (unsafeCoerce# (Prelude.reverse xs))+ Dict -> PatReverse (unsafeCoerce# (Prelude.reverse xs)) {-# INLINE unreverseTL #-} -mkRTL :: forall (xs :: [k])+mkRTL :: forall (k :: Type) (xs :: [k]) . TypeList xs- -> Evidence (RepresentableList xs)-mkRTL xs = reifyRepList xs E+ -> Dict (RepresentableList xs)+mkRTL xs = reifyRepList xs Dict {-# INLINE mkRTL #-} -data PatSnoc f xs where+data PatSnoc (f :: k -> Type) (xs :: [k]) where PatSNil :: PatSnoc f '[] PatSnoc :: TypedList f ys -> f y -> PatSnoc f (ys +: y) -unsnocTL :: forall f xs . TypedList f xs -> PatSnoc f xs+unsnocTL :: forall (k :: Type) (f :: k -> Type) (xs :: [k])+ . TypedList f xs -> PatSnoc f xs unsnocTL (TypedList [])- = case (unsafeCoerce# (E @(xs ~ xs)) :: Evidence (xs ~ '[])) of- E -> PatSNil+ = case unsafeEqTypes @_ @xs @'[] of+ Dict -> PatSNil unsnocTL (TypedList (x:xs))- = case (unsafeCoerce# (E @(xs ~ xs)) :: Evidence (xs ~ (Init xs +: Last xs))) of- E -> PatSnoc (unsafeCoerce# sy) (unsafeCoerce# y)+ = case unsafeEqTypes @_ @xs @(Init xs +: Last xs) of+ Dict -> PatSnoc (unsafeCoerce# sy) (unsafeCoerce# y) where (sy, y) = unsnoc x xs+ unsnoc :: Any -> [Any] -> ([Any], Any) unsnoc t [] = ([], t) unsnoc t (z:zs) = first (t:) (unsnoc z zs) {-# INLINE unsnocTL #-} -data PatCons f xs where+data PatCons (f :: k -> Type) (xs :: [k]) where PatCNil :: PatCons f '[] PatCons :: f y -> TypedList f ys -> PatCons f (y ': ys) -patTL :: forall f xs . TypedList f xs -> PatCons f xs+patTL :: forall (k :: Type) (f :: k -> Type) (xs :: [k])+ . TypedList f xs -> PatCons f xs patTL (TypedList [])- = case (unsafeCoerce# (E @(xs ~ xs)) :: Evidence (xs ~ '[])) of- E -> PatCNil+ = case unsafeEqTypes @_ @xs @'[] of+ Dict -> PatCNil patTL (TypedList (x : xs))- = case (unsafeCoerce# (E @(xs ~ xs)) :: Evidence (xs ~ (Head xs ': Tail xs))) of- E -> PatCons (unsafeCoerce# x) (unsafeCoerce# xs)+ = case unsafeEqTypes @_ @xs @(Head xs ': Tail xs) of+ Dict -> PatCons (unsafeCoerce# x) (unsafeCoerce# xs) {-# INLINE patTL #-} -intD :: Dim n -> Int-intD = (fromIntegral :: Word -> Int) . unsafeCoerce#+mkEVL :: forall (k :: Type) (c :: k -> Constraint) (xs :: [k])+ . DictList c xs -> Dict (All c xs, RepresentableList xs)+mkEVL U = Dict+mkEVL (Dict1 :* evs) = case mkEVL evs of Dict -> Dict -mkEVL :: forall (c :: k -> Constraint) (xs :: [k])- . EvidenceList c xs -> Evidence (All c xs, RepresentableList xs)-mkEVL U = E-mkEVL (E' :* evs) = case mkEVL evs of E -> E-#if __GLASGOW_HASKELL__ >= 802-#else-mkEVL _ = error "EvList/mkEVL: impossible argument"-#endif+_evList :: forall (k :: Type) (c :: k -> Constraint) (xs :: [k]) (f :: (k -> Type))+ . All c xs => TypedList f xs -> DictList c xs+_evList U = U+_evList (_ :* xs) = case _evList xs of evs -> Dict1 :* evs +unsafeEqTypes :: forall (k :: Type) (a :: k) (b :: k) . Dict (a ~ b)+unsafeEqTypes = unsafeCoerce# (Dict :: Dict (a ~ a)) -_evList :: forall (c :: k -> Constraint) (xs :: [k])- . All c xs => TypeList xs -> EvidenceList c xs-_evList U = U-_evList (_ :* xs) = case _evList xs of evs -> E' :* evs-#if __GLASGOW_HASKELL__ >= 802-#else-_evList _ = error "EvList/_evList: impossible argument"-#endif+dimValInt :: forall (k :: Type) (x :: k) . Dim x -> Int+dimValInt = fromIntegral . dimVal
− test/Numeric/DimTest.hs
@@ -1,86 +0,0 @@-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE ExplicitNamespaces #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeOperators #-}---- | Some GHC versions show incorrect warnings here:------ GHC 8.2 says "Pattern match has inaccessible right hand side"--- if our GADT-like patterns are matched nested:--- https://ghc.haskell.org/trac/ghc/ticket/14253------ GHC 8.0 says "Pattern match(es) are non-exhaustive"--- because it does not support COMPLETE pragmas yet.----module Numeric.DimTest (runTests) where--import Test.QuickCheck (quickCheckAll)--import Numeric.Dim-import Numeric.Type.Evidence----- | Try inference of type-level natural values via term-level binary functions.-testBinaryOp :: forall (a :: Nat) (b :: Nat) (c :: Nat)- . (Word -> Word -> Word)- -> (Dim a -> Dim b -> Dim c)- -> Dim a -> Dim b -> Bool-testBinaryOp fTerm fType da db- | a <- dimVal da- , b <- dimVal db- , Dx dr <- someDimVal (fTerm a b)- -- pattern-match against @SomeDim@ to extract a type-level natural Dim.- , True <- fTerm a b == dimVal (fType da db)- -- compare the term-level function and the type-level function results- -- as regular word values.- , Just E <- sameDim dr (fType da db)- -- now the type system knows that @c ~ fType a b@ and- -- we can use ordinary equality function (which is @const True@).- = dr == fType da db-testBinaryOp _ _ _ _ = False----prop_plusDim :: Word -> Word -> Bool-prop_plusDim a b = case (someDimVal a, someDimVal b) of- (Dx da, Dx db) -> testBinaryOp (+) plusDim da db---prop_timesDim :: Word -> Word -> Bool-prop_timesDim a b = case (someDimVal a, someDimVal b) of- (Dx da, Dx db) -> testBinaryOp (*) timesDim da db---prop_powerDim :: Word -> Word -> Bool-prop_powerDim a b = case ( someDimVal a- , someDimVal b- ) of- (Dx da, Dx db) -> testBinaryOp (^) powerDim da db--prop_minusDim :: Word -> Word -> Bool-prop_minusDim a' b'- | a <- max a' b'- , b <- min a' b'- , xda <- someDimVal a -- this is an unknown (Dim (XN 0))- , Dx db <- someDimVal b- , Just (Dx da) <- constrainBy db xda -- here da >= db- = a - b == dimVal (minusDim da db)-prop_minusDim _ _ = False-------return []-runTests :: IO Bool-runTests = $quickCheckAll
+ test/Numeric/Dimensions/DimTest.hs view
@@ -0,0 +1,159 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}++++module Numeric.Dimensions.DimTest (runTests) where++import Data.Constraint+import Data.Typeable+import Test.QuickCheck++import Numeric.Dimensions+import qualified Numeric.TypedList as TL+++-- | Try inference of type-level natural values via term-level binary functions.+testBinaryOp :: forall (a :: Nat) (b :: Nat) (c :: Nat)+ . (Word -> Word -> Word)+ -> (Dim a -> Dim b -> Dim c)+ -> Dim a -> Dim b -> Bool+testBinaryOp fTerm fType da db+ | a <- dimVal da+ , b <- dimVal db+ , Dx dr <- someDimVal (fTerm a b)+ -- pattern-match against @SomeDim@ to extract a type-level natural Dim.+ , True <- fTerm a b == dimVal (fType da db)+ -- compare the term-level function and the type-level function results+ -- as regular word values.+ , Just Dict <- sameDim dr (fType da db)+ -- now the type system knows that @c ~ fType a b@ and+ -- we can use ordinary equality function (which is @const True@).+ = dr == fType da db+testBinaryOp _ _ _ _ = False++++prop_plusDim :: Word -> Word -> Bool+prop_plusDim a b = case (someDimVal a, someDimVal b) of+ (Dx da, Dx db) -> testBinaryOp (+) plusDim da db+++prop_timesDim :: Word -> Word -> Bool+prop_timesDim a b = case (someDimVal a, someDimVal b) of+ (Dx da, Dx db) -> testBinaryOp (*) timesDim da db+++prop_powerDim :: Word -> Word -> Bool+prop_powerDim a b = case ( someDimVal a+ , someDimVal b+ ) of+ (Dx da, Dx db) -> testBinaryOp (^) powerDim da db++prop_minusDim :: Word -> Word -> Bool+prop_minusDim a' b'+ | a <- max a' b'+ , b <- min a' b'+ , xda <- someDimVal a -- this is an unknown (Dim (XN 0))+ , Dx (db :: Dim b) <- someDimVal b+ , Just (Dx da) <- constrainDim @_ @(XN b) xda -- here da >= db+ = a - b == dimVal (minusDim da db)+prop_minusDim _ _ = False+++-- | Matching against @Reverse@ pattern lets GHC know the reversion relation+-- at the type level.+-- That means the type system knows that reverse of reverse is the same list!+prop_reverseDims :: [Word] -> Property+prop_reverseDims xs+ | SomeDims ds <- someDimsVal xs+ = case ds of+ Reverse rds -> case rds of+ Reverse rrds -> ds === rrds+++prop_concatDims :: [Word] -> [Word] -> Property+prop_concatDims xs ys+ | SomeDims dxs <- someDimsVal xs+ , SomeDims dys <- someDimsVal ys+ = case TL.concat dxs dys of+ dxsys -> listDims dxsys === xs ++ ys+++-- | TODO: bring more evidence about list equality+prop_splitDims :: Word -> [Word] -> Property+prop_splitDims n xsys+ | SomeDims dxsys <- someDimsVal xsys+ , Dx dn <- someDimVal n+ -- TODO: hmm, this is an incomplete pattern even though+ -- Dn dn would not type check :(.+ , (xs, ys) <- splitAt (fromIntegral n) xsys+ = case TL.splitAt dn dxsys of+ (dxs, dys) -> listDims dxs === xs+ .&&. listDims dys === ys+ .&&. case stripPrefixDims dxs dxsys >>= sameDims dys of+ Nothing -> counterexample+ ("stripPrefixDims with " ++ show (dxs, dys, dxsys)) False+ Just Dict -> property True+ .&&. case stripSuffixDims dys dxsys >>= sameDims dxs of+ Nothing -> counterexample+ ("stripSuffixDims with " ++ show (dxs, dys, dxsys)) False+ Just Dict -> property True+ -- .&&. dxsys === TL.concat dxs dys+ | otherwise = property False+++prop_stripPrefixDims :: Int -> [Word] -> Property+prop_stripPrefixDims n l+ | SomeDims xsys@Dims <- someDimsVal l+ , SomeDims xs@Dims <- someDimsVal $ take (n `mod` (length l + 2)) l+ , Just ys@Dims <- stripPrefixDims xs xsys+ , Dict <- dimsAllEq xs+ , Dict <- dimsAllTypeable xs+ , Dict <- dimsAllTypeable xsys+ , Just ys'@Dims <- TL.stripPrefix xs xsys+ = case sameDims ys ys' of+ Nothing -> counterexample+ ("stripPrefix[Dims] discrepancy " ++ show (ys, ys')) False+ Just Dict -> property True+ | otherwise = counterexample "stripPrefix of take does not work!" False++prop_stripSuffixDims :: Int -> [Word] -> Property+prop_stripSuffixDims n l+ | SomeDims xsys@Dims <- someDimsVal l+ , SomeDims ys@Dims <- someDimsVal $ drop (n `mod` (length l + 2)) l+ , Just xs@Dims <- stripSuffixDims ys xsys+ , Dict <- dimsAllEq ys+ , Dict <- dimsAllTypeable ys+ , Dict <- dimsAllTypeable xsys+ , Just xs'@Dims <- TL.stripSuffix ys xsys+ = case sameDims xs xs' of+ Nothing -> counterexample+ ("stripSuffixDims[Dims] discrepancy " ++ show (xs, xs')) False+ Just Dict -> property True+ | otherwise = counterexample "stripSuffixDims of take does not work!" False+++dimsAllEq :: Dims (ns :: [Nat]) -> Dict (All Eq (Map Dim ns))+dimsAllEq U = Dict+dimsAllEq (D :* ds) | Dict <- dimsAllEq ds = Dict++dimsAllTypeable :: Dims (ns :: [Nat]) -> Dict (All Typeable ns)+dimsAllTypeable U = Dict+dimsAllTypeable ((D :: Dim n) :* ds)+ | Dict <- mapDict cls (Dict @(KnownDim n))+ , Dict <- dimsAllTypeable ds = Dict+++return []+runTests :: IO Bool+runTests = $quickCheckAll
− test/Numeric/Dimensions/DimsTest.hs
@@ -1,67 +0,0 @@-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE ExplicitNamespaces #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeOperators #-}----module Numeric.Dimensions.DimsTest (runTests) where--import Test.QuickCheck (quickCheckAll)--import Numeric.Dim-import Numeric.Dimensions.Dims-import qualified Numeric.TypedList as TL----- | Matching against @Reverse@ pattern lets GHC know the reversion relation--- at the type level.--- That means the type system knows that reverse of reverse is the same list!-prop_reverseDims :: [Word] -> Bool-prop_reverseDims xs- | SomeDims ds <- someDimsVal xs- = case ds of- Reverse rds -> case rds of- Reverse rrds -> ds == rrds---prop_concatDims :: [Word] -> [Word] -> Bool-prop_concatDims xs ys- | SomeDims dxs <- someDimsVal xs- , SomeDims dys <- someDimsVal ys- = case TL.concat dxs dys of- dxsys -> listDims dxsys == xs ++ ys----- | TODO: bring more evidence about list equality-prop_splitDims :: Word -> [Word] -> Bool-prop_splitDims n xsys- | SomeDims dxsys <- someDimsVal xsys- , Dx dn <- someDimVal n -- TODO: why this causes non-exhaustive patterns in GHC 8.2?- , (xs, ys) <- splitAt (fromIntegral n) xsys- = case TL.splitAt dn dxsys of- (dxs, dys) -> and- [ listDims dxs == xs- , listDims dys == ys- -- , dxsys == TL.concat dxs dys- ]---------return []-runTests :: IO Bool-runTests = $quickCheckAll
+ test/Numeric/Dimensions/IdxTest.hs view
@@ -0,0 +1,165 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}++module Numeric.Dimensions.IdxTest (runTests) where++import Control.Arrow+import Data.List+import Data.Maybe+import Test.QuickCheck (quickCheckAll)++import Numeric.Dimensions++minMaxSeq :: [(Word, Word)] -> ([Word], [Word])+minMaxSeq [] = ([], [])+minMaxSeq ((x, y):xs) = (min x y :) *** (max x y :) $ minMaxSeq xs++twoIdxsSeq :: [(Word, Word, Word)] -> ([Word], [Word], SomeDims)+twoIdxsSeq inputs = (take n is1, take n is2, someDimsVal (take n ds))+ where+ n = fst $ foldl findN (0, 1) ds+ findN (k, dd) d+ = let dd' = dd * d+ in if d <= niceLimit && dd' <= niceLimit+ then (k+1,dd') else (k, niceLimit+1)+ (is1, is2, ds) = unzip3 $ map reform inputs+ niceLimit = 100000+ reform :: (Word, Word, Word) -> (Word, Word, Word)+ reform (x, y, z)+ | z >= x && z >= y = (x, y, z + 1)+ | x >= z && x >= y = (y, z, x + 1)+ | otherwise = (x, z, y + 1)+++-- | Check successful cases+prop_idxsFromWords1 :: [(Word, Word)] -> Bool+prop_idxsFromWords1 ins+ | (xs, ys) <- minMaxSeq ins+ , SomeDims (KnownDims :: Dims ds) <- someDimsVal ys+ , mIs <- idxsFromWords @Nat @ds xs+ = or (zipWith (==) xs ys) || isJust mIs+ | otherwise+ = error "Impossible arguments"++-- | Check failing cases+prop_idxsFromWords2 :: [(Word, Word)] -> Bool+prop_idxsFromWords2 ins+ | (xs, ys) <- minMaxSeq ins+ , SomeDims (KnownDims :: Dims ds) <- someDimsVal xs+ , mIs <- idxsFromWords @Nat @ds ys+ = null xs || isNothing mIs+ | otherwise+ = error "Impossible arguments"++-- | Check if results of idxsFromWords are consistent with idxFromWord+prop_idxsFromWords3 :: [(Word, Word)] -> Bool+prop_idxsFromWords3 ins+ | (xs, ys) <- minMaxSeq ins+ , SomeDims (ds@KnownDims :: Dims ds) <- someDimsVal ys+ , mIs <- idxsFromWords @Nat @ds xs+ = Just False /= (go xs ds <$> mIs)+ | otherwise+ = error "Impossible arguments"+ where+ go :: forall (ns :: [Nat]) . [Word] -> Dims ns -> Idxs ns -> Bool+ go [] U U = True+ go (w:ws) (D :* ds) (i :* is)+ = Just i == idxFromWord w && go ws ds is+ go _ _ _ = False++multLimit :: Word+multLimit = floor $ sqrt (fromIntegral (maxBound :: Int) :: Double)++-- check for Word overflow+wouldNotOverflow :: [Word] -> Bool+wouldNotOverflow+ = and . snd . mapAccumR (\a e -> (a*e, a*e >= a && multLimit > a)) 1++prop_idxsFromEnum :: [(Word, Word)] -> Bool+prop_idxsFromEnum ins+ | (xs, ys) <- minMaxSeq ins+ , wouldNotOverflow ys+ , SomeDims (KnownDims :: Dims ds) <- someDimsVal ys+ , Just ids <- idxsFromWords @Nat @ds xs+ = ids == toEnum (fromEnum ids)+ | otherwise = True++prop_idxsSucc :: [(Word, Word)] -> Bool+prop_idxsSucc ins+ | (xs, ys) <- minMaxSeq ins+ , wouldNotOverflow ys+ , SomeDims (KnownDims :: Dims ds) <- someDimsVal ys+ , Just ids <- idxsFromWords @Nat @ds xs+ = ids == maxBound || fromEnum (succ ids) == succ (fromEnum ids)+ | otherwise = True++prop_idxsPred :: [(Word, Word)] -> Bool+prop_idxsPred ins+ | (xs, ys) <- minMaxSeq ins+ , wouldNotOverflow ys+ , SomeDims (KnownDims :: Dims ds) <- someDimsVal ys+ , Just ids <- idxsFromWords @Nat @ds xs+ = ids == minBound || fromEnum (pred ids) == pred (fromEnum ids)+ | otherwise = True++prop_idxsPredSucc :: [(Word, Word)] -> Bool+prop_idxsPredSucc ins+ | (xs, ys) <- minMaxSeq ins+ , SomeDims (KnownDims :: Dims ds) <- someDimsVal ys+ , Just ids <- idxsFromWords @Nat @ds xs+ = ids == minBound || ids == maxBound+ || ( succ (pred ids) == ids && pred (succ ids) == ids )+ | otherwise = True++prop_idxsEnumFrom :: [(Word, Word)] -> Bool+prop_idxsEnumFrom ins+ | (xs, ys) <- minMaxSeq ins+ , wouldNotOverflow ys+ , product ys < 100000+ , SomeDims (KnownDims :: Dims ds) <- someDimsVal ys+ , Just ids <- idxsFromWords @Nat @ds xs+ = [ids..] == map toEnum [fromEnum ids .. fromEnum (maxBound @(Idxs ds))]+ | otherwise = True++prop_idxsEnumFromTo :: [(Word, Word, Word)] -> Bool+prop_idxsEnumFromTo ins+ | (xs, ys, SomeDims (KnownDims :: Dims ds)) <- twoIdxsSeq ins+ , Just ids <- idxsFromWords @Nat @ds xs+ , Just jds <- idxsFromWords @Nat @ds ys+ = [ids..jds] == map toEnum [fromEnum ids .. fromEnum jds]+ | otherwise = True++prop_idxsEnumFromThen :: [(Word, Word, Word)] -> Bool+prop_idxsEnumFromThen ins+ | (xs, ys, SomeDims (KnownDims :: Dims ds)) <- twoIdxsSeq ins+ , Just ids <- idxsFromWords @Nat @ds xs+ , Just jds <- idxsFromWords @Nat @ds ys+ , lim <- if jds >= ids then maxBound else minBound :: Idxs ds+ = take 1000 [ids, jds ..]+ ==+ take 1000 (map toEnum [fromEnum ids, fromEnum jds .. fromEnum lim])+ | otherwise = True++prop_idxsEnumFromThenTo :: Bool -> [(Word, Word, Word)] -> Bool+prop_idxsEnumFromThenTo up ins+ | (xs, ys, SomeDims (KnownDims :: Dims ds)) <- twoIdxsSeq ins+ , Just ids <- idxsFromWords @Nat @ds xs+ , Just jds <- idxsFromWords @Nat @ds ys+ , lim <- if up then maxBound else minBound :: Idxs ds+ = take 1000 [ids, jds .. lim]+ ==+ take 1000 (map toEnum [fromEnum ids, fromEnum jds .. fromEnum lim])+ | otherwise = True++return []+runTests :: IO Bool+runTests = $quickCheckAll
test/Spec.hs view
@@ -1,17 +1,17 @@ module Main (tests, main) where -import System.Exit-import Distribution.TestSuite+import Distribution.TestSuite+import System.Exit -import qualified Numeric.DimTest-import qualified Numeric.Dimensions.DimsTest+import qualified Numeric.Dimensions.DimTest+import qualified Numeric.Dimensions.IdxTest -- | Collection of tests in detailed-0.9 format tests :: IO [Test] tests = return- [ test "Dim" Numeric.DimTest.runTests- , test "Dims" Numeric.Dimensions.DimsTest.runTests+ [ test "Dim" Numeric.Dimensions.DimTest.runTests+ , test "Idx" Numeric.Dimensions.IdxTest.runTests ] @@ -20,16 +20,17 @@ -- | Run tests as exitcode-stdio-1.0 main :: IO () main = do+ putStrLn "" ts <- tests trs <- mapM (\(Test ti) ->(,) (name ti) <$> run ti) ts- case filter (not . isGood) trs of+ case filter (not . isGood . snd) trs of [] -> exitSuccess xs -> do putStrLn $ "Failed tests: " ++ unwords (fmap fst xs) exitFailure where- isGood (_, Finished Pass) = True- isGood _ = False+ isGood (Finished Pass) = True+ isGood _ = False -- | Convert QuickCheck props into Cabal tests