| Copyright | (c) Justin Le 2024 |
|---|---|
| License | MIT |
| Maintainer | justin@jle.im |
| Stability | unstable |
| Portability | non-portable |
| Safe Haskell | Safe-Inferred |
| Language | Haskell2010 |
GHC.TypeLits.Witnesses
Description
This module essentially provides a lightweight subset of the
singletons library specifically for Nat and Symbol, from
GHC.TypeLits.
Its main functionality is for first-class manipulation of KnownNat and
KnownSymbol constraints. For example, in general, if you have
, GHC can't infer KnownNat n. And, if you have
both KnownNat (n + 1) and KnownNat n, GHC can't infer KnownNat m'KnownNat (n
+ m).
This can be annoying when dealing with libraries and applications where
one regularly adds and subtracts type-level nats and expects KnownNat
instances to follow. For example, vector concatenation of
length-encoded vector types can be:
concat :: (KnownNatn,KnownNatm) => Vector n a -> Vector m a -> Vector (n + m) a
But, now n + m does not have a KnownNat instance...which makes
operations like this much less useful.
Usually, the easiest way to get around this is to use a typechecker plugin, like https://hackage.haskell.org/package/ghc-typelits-knownnat. However, we can do this without the help of a typechecker plugin using first-class values, at the cost of some increased verbosity.
We introduce , which is a term-level witness of knownnat-ness
that can be manipulated as a first-class value.SNat n
If we have , we can construct an KnownNat n:SNat n
SNat :: KnownNat n -> SNat n
Furthermore, if we have an , we can pattern match on the
SNat nSNat constructor to get a constraint:KnownNat n
myFunc :: SNat n -> Bool myFunc SNat = ... -- in this body, we have `KnownNat n`
So if we have and KnownNat n, we can get KnownNat m by using KnownNat
(n + m)%+, which adds together SNats:
case (SNat :: SNat n) %+ (SNat :: SNat m) of SNat -> -- in this branch, we have `KnownNat (n + m)`
Note that this module converts between SNat and Natural, and not
SNat and Integer, in GHC.TypeNats-style.
Of course, all of this functionality is provided by the singletons
library, in Data.Singletons.TypeLits. This module can be useful if
you want a lightweight alternative without the full might of
singletons. The main benefit of the singletons library is providing
a unified interface for singletons of all different kinds/types, and
not just Natural and String.
Synopsis
- data SNat n = KnownNat n => SNat
- data SomeNat where
- data Natural where
- fromSNat :: SNat n -> Natural
- withKnownNat :: SNat n -> (KnownNat n => r) -> r
- withSomeNat :: Natural -> (forall n. SNat n -> r) -> r
- toSomeNat :: Natural -> SomeNat
- (%+) :: SNat n -> SNat m -> SNat (n + m)
- (%-) :: SNat n -> SNat m -> SNat (n - m)
- minusSNat :: SNat n -> SNat m -> Either (CmpNat n m :~: 'LT) (SNat (n - m))
- minusSNat_ :: SNat n -> SNat m -> Maybe (SNat (n - m))
- (%*) :: SNat n -> SNat m -> SNat (n * m)
- (%^) :: SNat n -> SNat m -> SNat (n ^ m)
- (%<=?) :: SNat n -> SNat m -> n :<=? m
- sCmpNat :: SNat n -> SNat m -> SCmpNat n m
- unsafeLiftNatOp1 :: (Natural -> Natural) -> SNat n -> SNat m
- unsafeLiftNatOp2 :: (Natural -> Natural -> Natural) -> SNat n -> SNat m -> SNat o
- data SSymbol n = KnownSymbol n => SSymbol
- data SomeSymbol where
- pattern SomeSymbol_ :: SSymbol n -> SomeSymbol
- pattern FromSSymbol :: SSymbol n -> String
- fromSSymbol :: SSymbol n -> String
- withKnownSymbol :: SSymbol n -> (KnownSymbol n => r) -> r
- withSomeSymbol :: String -> (forall n. SSymbol n -> r) -> r
- toSomeSymbol :: String -> SomeSymbol
Nats
An is a witness for SNat n.KnownNat n
This means that if you pattern match on the SNat constructor, in that
branch you will have a constraint.KnownNat n
myFunc :: SNat n -> Bool myFunc SNat = ... -- in this body, we have `KnownNat n`
This is essentially a singleton for Nat, and stands in for the
singletons SNat and Sing types.
Note that this type exists in base as of base 4.18.0 (GHC 9.6)
This type represents unknown type-level natural numbers.
Since: base-4.10.0.0
Bundled Patterns
| pattern SomeNat_ :: SNat n -> SomeNat | A useful pattern synonym for matching on a A layer of compatibility letting us use the original This stands in for the singletons |
Natural number
Invariant: numbers <= 0xffffffffffffffff use the NS constructor
Bundled Patterns
| pattern FromSNat :: SNat n -> Natural | A useful pattern synonym for matching on a myFunc :: Natural -> Bool
myFunc (FromSNat x) = ... -- x is `SNat n`, with It can be used as a function, as well, to convert an This stands in for the singletons |
Instances
| Data Natural | Since: base-4.8.0.0 |
Defined in Data.Data Methods gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Natural -> c Natural # gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c Natural # toConstr :: Natural -> Constr # dataTypeOf :: Natural -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c Natural) # dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Natural) # gmapT :: (forall b. Data b => b -> b) -> Natural -> Natural # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Natural -> r # gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Natural -> r # gmapQ :: (forall d. Data d => d -> u) -> Natural -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> Natural -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> Natural -> m Natural # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Natural -> m Natural # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Natural -> m Natural # | |
| Enum Natural | Since: base-4.8.0.0 |
| Num Natural | Note that Since: base-4.8.0.0 |
| Read Natural | Since: base-4.8.0.0 |
| Integral Natural | Since: base-4.8.0.0 |
Defined in GHC.Real | |
| Real Natural | Since: base-4.8.0.0 |
Defined in GHC.Real Methods toRational :: Natural -> Rational # | |
| Show Natural | Since: base-4.8.0.0 |
| Eq Natural | |
| Ord Natural | |
| TestCoercion SNat | Since: base-4.18.0.0 |
Defined in GHC.TypeNats | |
| TestEquality SNat | Since: base-4.18.0.0 |
Defined in GHC.TypeNats | |
| TestEquality SNat Source # | |
Defined in GHC.TypeLits.Witnesses | |
| GCompare SNat | |
| GCompare SNat Source # | |
| GEq SNat | |
| GEq SNat Source # | |
| GShow SNat | |
Defined in Data.GADT.Internal Methods gshowsPrec :: forall (a :: k). Int -> SNat a -> ShowS # | |
| GShow SNat Source # | |
Defined in GHC.TypeLits.Witnesses Methods gshowsPrec :: forall (a :: k). Int -> SNat a -> ShowS # | |
| type Compare (a :: Natural) (b :: Natural) | |
Defined in Data.Type.Ord | |
withKnownNat :: SNat n -> (KnownNat n => r) -> r Source #
Given an and a value that would require a SNat n
instance, create that value.KnownNat n
This stands in for the function of the same name from Data.Singletons.TypeLits.
withSomeNat :: Natural -> (forall n. SNat n -> r) -> r Source #
Promote ("reify") a Natural to an , by providing
a continuation that would handle it in a way that is polymorphic over
all possible SNat nn.
This stands in the singletons withSomeSing function.
toSomeNat :: Natural -> SomeNat Source #
Promote ("reify") a Natural to an existentially hidden
inside a SNat nSomeNat. To use it, pattern match using SomeNat_.
This stands in the singletons toSomeSing function.
Operations
(%+) :: SNat n -> SNat m -> SNat (n + m) Source #
Addition of SNats.
This also will provide the correct KnownNat instance for , so can be used as a way to "add" SNat (n
+ m)KnownNat instances.
This stands in for the function with the same name from Data.Singletons.Prelude.Num.
(%-) :: SNat n -> SNat m -> SNat (n - m) Source #
Subtraction of SNats. Note that this is unsafe, as will trigger
a run-time underflow if m is bigger than n even though it will always
succeed at compiletime.
This also will provide the correct KnownNat instance for , so can be used as a way to "subtract" SNat (n
- m)KnownNat instances.
This stands in for the function with the same name from Data.Singletons.Prelude.Num.
(%*) :: SNat n -> SNat m -> SNat (n * m) Source #
Multiplication of SNats.
This also will provide the correct KnownNat instance for , so can be used as a way to "multiply" SNat (n
* m)KnownNat instances.
This stands in for the function with the same name from Data.Singletons.Prelude.Num.
(%^) :: SNat n -> SNat m -> SNat (n ^ m) Source #
Exponentiation of SNats.
This also will provide the correct KnownNat instance for , so can be used as a way to "exponentiate" SNat (n
^ m)KnownNat instances.
This stands in for the function with the same name from Data.Singletons.TypeLits.
Compare
(%<=?) :: SNat n -> SNat m -> n :<=? m Source #
Compare n and m, categorizing them into one of the constructors of
:<=?.
sCmpNat :: SNat n -> SNat m -> SCmpNat n m Source #
Compare n and m, categorizing them into one of the constructors of
SCmpNat.
Unsafe
unsafeLiftNatOp1 :: (Natural -> Natural) -> SNat n -> SNat m Source #
Lift a unary operation to act on an that returns an SNat n. The function given must properly describe the relationship between
SNat
mn and m.
For example:
double :: SNat n -> SNat (n * 2) double = unsafeLiftNatOp1 (*2)
The correctness of the relationship is not checked, so be aware that this can cause programs to break.
unsafeLiftNatOp2 :: (Natural -> Natural -> Natural) -> SNat n -> SNat m -> SNat o Source #
Lift a binary operation to act on an and SNat n that
returns an SNat m. The function given must properly describe the
relationship between SNat on, m, and o.
For example:
multiply :: SNat n -> SNat m -> SNat (n * m) multiply = unsafeLiftNatOp2 (*)
The correctness of the relationship is not checked, so be aware that this can cause programs to break.
Symbols
An is a witness for SSymbol n.KnownSymbol n
This means that if you pattern match on the SSymbol constructor, in that
branch you will have a constraint.KnownSymbol n
myFunc :: SSymbol n -> Bool myFunc SSymbol = ... -- in this body, we have `KnownSymbol n`
This is essentially a singleton for Symbol, and stands in for the
singletons SSymbol and Sing types.
Note that this type exists in base as of base 4.18.0 (GHC 9.6)
Constructors
| KnownSymbol n => SSymbol |
Instances
| TestEquality SSymbol Source # | |
Defined in GHC.TypeLits.Witnesses | |
| GCompare SSymbol Source # | |
| GEq SSymbol Source # | |
| GShow SSymbol Source # | |
Defined in GHC.TypeLits.Witnesses Methods gshowsPrec :: forall (a :: k). Int -> SSymbol a -> ShowS # | |
| Show (SSymbol n) Source # | |
| Eq (SSymbol n) Source # | |
| Ord (SSymbol n) Source # | |
data SomeSymbol where #
This type represents unknown type-level symbols.
Bundled Patterns
| pattern SomeSymbol_ :: SSymbol n -> SomeSymbol | A useful pattern synonym for matching on a A layer of compatibility letting us use the original This stands in for the singletons |
Instances
| Read SomeSymbol | Since: base-4.7.0.0 |
Defined in GHC.TypeLits Methods readsPrec :: Int -> ReadS SomeSymbol # readList :: ReadS [SomeSymbol] # readPrec :: ReadPrec SomeSymbol # readListPrec :: ReadPrec [SomeSymbol] # | |
| Show SomeSymbol | Since: base-4.7.0.0 |
Defined in GHC.TypeLits Methods showsPrec :: Int -> SomeSymbol -> ShowS # show :: SomeSymbol -> String # showList :: [SomeSymbol] -> ShowS # | |
| Eq SomeSymbol | Since: base-4.7.0.0 |
Defined in GHC.TypeLits | |
| Ord SomeSymbol | Since: base-4.7.0.0 |
Defined in GHC.TypeLits Methods compare :: SomeSymbol -> SomeSymbol -> Ordering # (<) :: SomeSymbol -> SomeSymbol -> Bool # (<=) :: SomeSymbol -> SomeSymbol -> Bool # (>) :: SomeSymbol -> SomeSymbol -> Bool # (>=) :: SomeSymbol -> SomeSymbol -> Bool # max :: SomeSymbol -> SomeSymbol -> SomeSymbol # min :: SomeSymbol -> SomeSymbol -> SomeSymbol # | |
pattern FromSSymbol :: SSymbol n -> String Source #
A useful pattern synonym for matching on a String as if it "were"
a SSymbol:
myFunc :: String -> Bool
myFunc (FromSSymbol x) = ... -- x is `SSymbol n`, with n coming from the input
It can be used as a function, as well, to convert an back
into the SSymbol nString that it represents.
This stands in for the singletons FromSing pattern synonym, except
it matches on a String instead of a Text.
fromSSymbol :: SSymbol n -> String Source #
withKnownSymbol :: SSymbol n -> (KnownSymbol n => r) -> r Source #
Given an and a value that would require a SSymbol n
instance, create that value.KnownSymbol n
This stands in for the function of the same name from Data.Singletons.TypeLits.
withSomeSymbol :: String -> (forall n. SSymbol n -> r) -> r Source #
Promote ("reify") a String to an , by providing
a continuation that would handle it in a way that is polymorphic over
all possible SSymbol nn.
This stands in the singletons withSomeSing function, except it takes
a String instead of Text.
toSomeSymbol :: String -> SomeSymbol Source #
Promote ("reify") a String to an existentially hidden
inside a SSymbol nSomeNat. To use it, pattern match using SomeSymbol_.
This stands in the singletons toSomeSing function, except it takes
a String instead of Text.