Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
Type-nat utilities.
We take Peano numbers as base for operations because they make it much easer to prove things to compiler. Their performance does not seem to introduce a problem, because we use nats primarily along with stack which is a linked list with similar performance characteristics.
Many of things we introduce here are covered in type-natural
package,
but unfortunatelly it does not work with GHC 8.6 at the moment of writing
this module. We use Data.Vinyl as source of Peano Nat
for now.
Synopsis
- type Peano = Nat
- pattern S :: !Nat -> Nat
- pattern Z :: Nat
- type family ToPeano (n :: Nat) :: Peano where ...
- type family FromPeano (n :: Peano) :: Nat where ...
- data SingNat :: Nat -> Type where
- peanoSing :: forall (n :: Nat). SingIPeano n => SingNat (ToPeano n)
- peanoSing' :: forall (n :: Nat). KnownNat n => SingNat (ToPeano n)
- withPeanoSingI :: forall (n :: Nat) r. KnownNat n => (SingIPeano n => r) -> r
- withSomePeano :: Natural -> (forall n. (KnownNat n, SingIPeano n) => Proxy n -> r) -> r
- type IsoNatPeano (n :: Nat) (p :: Peano) = (n ~ FromPeano p, ToPeano n ~ p)
- type SingIPeano (n :: Nat) = SingI (ToPeano n)
- type family (x :: Peano) > (y :: Peano) :: Bool where ...
- type family (x :: Peano) >= (y :: Peano) :: Bool where ...
- peanoSingDecrement :: Sing n -> Maybe (Sing (Decrement n))
- peanoSingAdd :: SingNat n -> SingNat m -> SingNat (AddPeano n m)
- type family Decrement (a :: Peano) :: Peano where ...
- type family AddPeano (n :: Peano) (m :: Peano) :: Peano where ...
- type family SubPeano (n :: Peano) (m :: Peano) :: Peano where ...
- type family MinPeano (n :: Peano) (m :: Peano) :: Peano where ...
- type family MaxPeano (n :: Peano) (m :: Peano) :: Peano where ...
- type family Length l :: Peano where ...
- type family At (n :: Peano) s where ...
- type family Drop (n :: Peano) (s :: [k]) :: [k] where ...
- type family LazyTake n xs where ...
- type family Take (n :: Peano) (s :: [k]) :: [k] where ...
- type family Head (xs :: [k]) :: k where ...
- type family Tail (xs :: [a]) :: [a] where ...
- type family IsLongerThan (l :: [k]) (a :: Peano) :: Bool where ...
- type LongerThan l a = IsLongerThan l a ~ 'True
- class (RequireLongerThan' l a, LongerThan l a) => RequireLongerThan (l :: [k]) (a :: Peano)
- type family IsLongerOrSameLength (l :: [k]) (a :: Peano) :: Bool where ...
- type LongerOrSameLength l a = IsLongerOrSameLength l a ~ 'True
- class (RequireLongerOrSameLength' l a, LongerOrSameLength l a) => RequireLongerOrSameLength (l :: [k]) (a :: Peano)
- requireLongerThan :: Rec any stk -> Sing n -> Maybe (Dict (RequireLongerThan stk n))
- requireLongerOrSameLength :: Rec any stk -> Sing n -> Maybe (Dict (RequireLongerOrSameLength stk n))
- isGreaterThan :: Sing a -> Sing b -> Maybe (Dict ((a > b) ~ 'True))
- isGreaterEqualThan :: Sing a -> Sing b -> Maybe (Dict ((a >= b) ~ 'True))
- additivity :: forall k m n. AddPeano k ('S m) ~ n => SingNat k -> (n > k) :~: 'True
- associativity :: forall y x. SingNat x -> AddPeano x ('S y) :~: 'S (AddPeano x y)
- minIdempotency :: SingNat n -> MinPeano n n :~: n
- commutativity :: SingNat x -> SingNat y -> AddPeano x y :~: AddPeano y x
- transitivity :: ((x >= y) ~ 'True, (y > z) ~ 'True) => SingNat x -> SingNat y -> SingNat z -> (x > z) :~: 'True
- toNatural :: Peano -> Natural
- someSingNat :: Natural -> SomeSing Peano
General
peanoSing :: forall (n :: Nat). SingIPeano n => SingNat (ToPeano n) Source #
Get the peano singleton for a given type-level nat literal.
>>>
peanoSing @2
SS (SS SZ)
withPeanoSingI :: forall (n :: Nat) r. KnownNat n => (SingIPeano n => r) -> r Source #
Run a computation requiring SingI (ToPeano n)
in a context which only has
KnownNat n
. Mostly useful when used with SomeNat
withSomePeano :: Natural -> (forall n. (KnownNat n, SingIPeano n) => Proxy n -> r) -> r Source #
Lift a given term-level Natural
to the type level for a given computation. The computation is
expected to accept a Proxy
for the sake of convenience: it's easier to get at the type-level
natural with ScopedTypeVariables
when pattern-matching on the proxy, e.g.
(x :: Natural) `withSomePeano` \(_ :: Proxy n) -> doSomeNatComputation @n
Utility type synonyms
type IsoNatPeano (n :: Nat) (p :: Peano) = (n ~ FromPeano p, ToPeano n ~ p) Source #
A constraint asserting that GHC's Nat
n
and Peano
p
are the same (up to an
isomorphism)
Peano Arithmetic
type family SubPeano (n :: Peano) (m :: Peano) :: Peano where ... Source #
Peano
naturals subtraction
type family MinPeano (n :: Peano) (m :: Peano) :: Peano where ... Source #
Out of two Peano
naturals, return the smaller one
type family MaxPeano (n :: Peano) (m :: Peano) :: Peano where ... Source #
Out of two Peano
naturals, return the larger one
Lists
type family LazyTake n xs where ... Source #
A "lazier" version of Take
. LazyTake n xs
will always produce
a list of exactly n
elements. If xs
has less than n
elements, then
some of the elements of the result will be stuck. Similarly, if some tail
of xs
is stuck or ambiguous, then elements of the result past that point
will be stuck.
LazyTake (ToPeano
4) '[1,2,3,4,5] ~ '[1,2,3,4]
LazyTake (ToPeano 4) (1 ': 2 ': 3 ': 4 ': Any) ~ '[1,2,3,4]
LazyTake (ToPeano 4) '[1,2] ~
'[1, 2, Head '[], Head (Tail '[])]
LazyTake
is often better than Take
for driving type inference.
For example, given the constraint
xs ~ Take (ToPeano 3) xs ++ q ': Drop (ToPeano 4) xs
GHC can't infer anything about the shape of xs
. However, the constraint
xs ~ LazyTake (ToPeano 3) xs ++ q ': Drop (ToPeano 4) xs
will allow GHC to infer
xs ~ x1 ': x2 ': x3 ': q ': Drop (ToPeano 4) xs
type family Take (n :: Peano) (s :: [k]) :: [k] where ... Source #
Morley-specific utils
type family IsLongerThan (l :: [k]) (a :: Peano) :: Bool where ... Source #
Comparison of type-level naturals, as a function.
It is as lazy on the list argument as possible - there is no need to know the whole list if the natural argument is small enough. This property is important if we want to be able to extract reusable parts of code which are aware only of relevant part of stack.
IsLongerThan (_ ': _) 'Z = 'True | |
IsLongerThan (_ ': xs) ('S a) = IsLongerThan xs a | |
IsLongerThan '[] _ = 'False |
type LongerThan l a = IsLongerThan l a ~ 'True Source #
Comparison of type-level naturals, as a constraint.
class (RequireLongerThan' l a, LongerThan l a) => RequireLongerThan (l :: [k]) (a :: Peano) Source #
Instances
(RequireLongerThan' l a, LongerThan l a) => RequireLongerThan (l :: [k]) a Source # | |
Defined in Morley.Util.Peano |
type family IsLongerOrSameLength (l :: [k]) (a :: Peano) :: Bool where ... Source #
Similar to IsLongerThan
, but returns True
when list length
equals to the passed number.
IsLongerOrSameLength _ 'Z = 'True | |
IsLongerOrSameLength (_ ': xs) ('S a) = IsLongerOrSameLength xs a | |
IsLongerOrSameLength '[] ('S _) = 'False |
type LongerOrSameLength l a = IsLongerOrSameLength l a ~ 'True Source #
IsLongerOrSameLength
in form of constraint that gives most
information to GHC.
class (RequireLongerOrSameLength' l a, LongerOrSameLength l a) => RequireLongerOrSameLength (l :: [k]) (a :: Peano) Source #
We can have
`RequireLongerOrSameLength = (RequireLongerOrSameLength' l a, LongerOrSameLength l a)`,
but apparently the printed error message can be caused by LongerOrSameLength
rather than RequireLongerOrSameLength'
.
We do not know for sure how it all works, but we think that if we require constraint X before
Y (using multiple `=>`s) then X will always be evaluated first.
Instances
(RequireLongerOrSameLength' l a, LongerOrSameLength l a) => RequireLongerOrSameLength (l :: [k]) a Source # | |
Defined in Morley.Util.Peano |
Length constraints Dict
ionaries
requireLongerThan :: Rec any stk -> Sing n -> Maybe (Dict (RequireLongerThan stk n)) Source #
requireLongerOrSameLength :: Rec any stk -> Sing n -> Maybe (Dict (RequireLongerOrSameLength stk n)) Source #
Length constraints Dict
ionaries
Inductive proofs
additivity :: forall k m n. AddPeano k ('S m) ~ n => SingNat k -> (n > k) :~: 'True Source #
Proof that for naturals, k + (m + 1) = n
entails n > k
associativity :: forall y x. SingNat x -> AddPeano x ('S y) :~: 'S (AddPeano x y) Source #
Proof that for naturals, x + (y + 1) = (x + y) + 1
commutativity :: SingNat x -> SingNat y -> AddPeano x y :~: AddPeano y x Source #
Proof that x + y = y + x
transitivity :: ((x >= y) ~ 'True, (y > z) ~ 'True) => SingNat x -> SingNat y -> SingNat z -> (x > z) :~: 'True Source #
Proof that for naturals, x >= y > z
implies x > z
Helpers
Orphan instances
Data Nat Source # | |
gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Nat -> c Nat # gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c Nat # dataTypeOf :: Nat -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c Nat) # dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Nat) # gmapT :: (forall b. Data b => b -> b) -> Nat -> Nat # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Nat -> r # gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Nat -> r # gmapQ :: (forall d. Data d => d -> u) -> Nat -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> Nat -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> Nat -> m Nat # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Nat -> m Nat # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Nat -> m Nat # | |
Generic Nat Source # | |
Show Nat Source # | |
NFData Nat Source # | |
Eq Nat Source # | |
SingKind Nat Source # | |
SDecide Nat => SDecide Nat Source # | |
SingI 'Z Source # | |
SingI1 'S Source # | |
SingI n => SingI ('S n :: Nat) Source # | |