-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/
-- | Integer singletons with flexible representation
--
-- This provides singletons-style witnesses for type-level integers, and
-- some limited arithmetic operations on them. Instead of working with
-- (invisible, implicitly-passed) KnownNat instances, you can work
-- with (visible, explicitly-mentioned) SNumber values, and can
-- freely convert between the two forms.
--
-- This primarily exists in support of dependent-literals-plugin.
@package snumber
@version 0.3.0
-- | Runtime witnesses of type-level integers.
module Data.SNumber
-- | SNumber a n is a runtime representation of the value of
-- n.
--
-- For N# n :: SNumber a n and N# m :: SNumber a m, the
-- following must hold:
--
--
-- - n ~ m iff n == m (according to the Eq
-- instance of a).
-- - CmpInteger m n ~ 'LT iff compare m n == LT
-- (according to Ord).
-- - CmpInteger m n ~ 'EQ iff compare m n == EQ.
-- - CmpInteger m n ~ 'GT iff compare m n == GT.
-- - toInteger n == integerVal @n.
-- - a upholds the Ord laws.
--
--
-- These are exactly the set of things we're willing to
-- unsafeCoerce proofs for. It is unsafe to construct an
-- SNumber that violates these by any means.
--
-- Note that the first requirement means that you must never construct
-- N# 0 :: SNumber _ ('Neg 0), because that would prove that
-- 'Neg 0 ~ 'Pos 0. In practice, we largely ignore the existence
-- of 'Neg 0: trySNumber (and, by extension, the instance
-- derivation via KnownInteger) will throw a runtime error when
-- trying to construct 'Neg 0, and SafeSNumber instances
-- explicitly exclude 'Neg 0 with type-level checks.
--
-- There are six main ways to introduce an SNumber, from the
-- cartesian product of several choices
--
--
-- - How do you validate that the value is in-bounds for the
-- representation type?
- If by runtime checks, the function name
-- has a "try" infix.
- If by trusting the caller blindly, the
-- function name has an "unsafe" prefix and an "Unchecked"
-- infix.
- If by type-level bounds checks, the function name has
-- neither of these.
-- - How do you validate that the runtime Integer value matches the
-- type-level Integer?
- If by trusting the user to pass in the
-- right Integer, the function has an "unsafe" prefix and a "Mk" infix:
-- we're "making" the SNumber from a runtime value rather than
-- deriving it from KnownNat.
- If by getting it from a KnownNat
-- instance, the function name doesn't have that infix.
--
--
-- Thus:
--
--
--
-- Finally, there's one other way to get an SNumber: by asking the
-- constraint solver to give you one, with a KnownSNumber class
-- and its snumberVal method. Currently, this will be solved
-- automatically from KnownNat by using trySNumber, and of
-- course it can be solved from a matching instance in the function's
-- context (which compiles to an a parameter for
-- KnownSNumber a n).
data SNumber a (n :: Integer)
-- | Treat SNumber as if it were a GADT containing a
-- KnownSNumber instance.
pattern SNumber :: forall (n :: Integer) a. SNumberRepr a => KnownSNumber a n => SNumber a n
-- | Create an SNumber for n, with no safety measures
-- whatsoever.
--
-- This pattern is identical to the newtype constructor of SNumber
-- except that it isn't actualy a newtype constructor, so having it in
-- scope doesn't allow unsound coercions across SNumber types.
pattern N# :: forall (n :: Integer) a. a -> SNumber a n
-- | A unidirectional pattern for matching SNumbers.
--
-- This allows the pseudo-field-selector unSNumber to be exported
-- bundled with SNumber, so it can be imported by
-- SNumber(..) as if it were a normal field selector of a record
-- definition. If this were done as part of N#, it'd allow
-- unsafely changing an SNumber's representation without using any
-- identifiers that indicate unsafety, by way of record update syntax.
pattern SN :: forall (n :: Integer) a. a -> SNumber a n
-- | The class of types that are suitable for use as integer value
-- witnesses.
--
-- Implementing an instance of this class amounts to asserting that the
-- type and its Integral, Ord, and Eq instances
-- uphold the requirements of SNumber, for any integer n
-- that satisfies SafeSNumber a n.
--
-- Furthermore, it requires that every value of a is an integer,
-- i.e. that forall x :: a. exists y :: Integer. x == fromInteger y,
-- toInteger x == y. This ensures we can wrap any a in
-- SomeSNumberVal and be sure it corresponds to a valid
-- K.Integer.
class Integral a => SNumberRepr a where {
-- | SafeSNumber a n witnesses that N# n is a
-- valid SNumber a n.
type family SafeSNumber a :: Integer -> Constraint;
}
-- | Construct an SNumber, doing all validation at the type level.
--
-- This is completely safe and cannot raise runtime errors.
snumber :: forall n a. (SNumberRepr a, SafeSNumber a n, KnownInteger n) => SNumber a n
-- | Create an SNumber for n, if it's faithfully
-- represented by a.
--
-- This is completely safe, but it may raise runtime errors, because it
-- tests at runtime whether a can represent n
-- correctly.
trySNumber :: forall n a. (SNumberRepr a, KnownInteger n) => Maybe (SNumber a n)
-- | Create an SNumber from a KnownInteger constraint without
-- any checks.
--
-- This will cause type unsoundness if the value is not correctly
-- represented by a or if the instances of a do not
-- behave according to the safety requirements described on
-- SNumber.
unsafeUncheckedSNumber :: forall n a. (Num a, KnownInteger n) => SNumber a n
-- | Semi-safely construct an SNumber as if by N#.
--
-- Callers must ensure that the a argument is fromInteger
-- (integerVal n) (semantically, not syntactically:
-- unsafeSNumber ('Pos 42) 42 is fine and is in fact the
-- intended use case).
--
-- The extra constraint here compared to N# ensures that if you
-- write unsafeMkSNumber @n (fromInteger n), the result is
-- either a valid SNumber or a type error. In particular, the
-- cases this rules out are those where toInteger (fromInteger n ::
-- a) /= n or where fromInteger m :: a == fromInteger n
-- does not imply m == n.
unsafeMkSNumber :: forall n a. SafeSNumber a n => a -> SNumber a n
-- | Create an SNumber for n, if it's faithfully
-- represented by a.
--
-- As with unsafeMkSNumber, this trusts you to pass integerVal
-- @n, and violating that will lead to type unsoundness.
--
-- This tests at runtime whether a represents n
-- correctly.
unsafeTryMkSNumber :: forall n a. SNumberRepr a => Integer -> Maybe (SNumber a n)
-- | Create an SNumber for n, with no safety measures
-- whatsoever.
unsafeUncheckedMkSNumber :: forall n a. a -> SNumber a n
-- | An SNumber with an existential Integer type parameter.
data SomeSNumber a
SomeSNumber :: SNumber a n -> SomeSNumber a
-- | Create an SNumber a from any value of type a.
--
-- Since SNumberRepr guarantees every a value is an
-- integer, we can freely wrap up a value in an SNumber with
-- existential Integer type parameter.
someSNumberVal :: SNumberRepr a => a -> SomeSNumber a
-- | Like someSNumberVal, but in quantified CPS style rather than
-- GADT style.
withSNumber :: SNumberRepr a => a -> (forall n. SNumber a n -> r) -> r
-- | Compare two type-level Integers using their runtime witnesses.
compareSNumber :: forall m n a. Ord a => SNumber a m -> SNumber a n -> OrderingI m n
-- | Test equality of two type-level Integers using their runtime
-- witnesses.
sameSNumber :: Eq a => SNumber a m -> SNumber a n -> Maybe (m :~: n)
-- | Arithmetic ops with overflow detection.
--
-- Laws:
--
--
-- overflowAdd x y = (False, xy) => toInteger xy ===
-- toInteger x + toInteger y
-- overflowSub x y = (False, xy) => toInteger xy ===
-- toInteger x - toInteger y
-- overflowMul x y = (False, xy) => toInteger xy ===
-- toInteger x * toInteger y
--
--
-- This is used for arithmetic on SNumber runtime values, so
-- creating incorrect instances is type-unsafe.
class Integral a => OverflowArith a
overflowAdd :: OverflowArith a => a -> a -> (Bool, a)
overflowSub :: OverflowArith a => a -> a -> (Bool, a)
overflowMul :: OverflowArith a => a -> a -> (Bool, a)
-- | Compute a runtime witness of m + n, or Nothing.
tryAdd :: (SNumberRepr a, OverflowArith a) => SNumber a m -> SNumber a n -> Maybe (SNumber a (m + n))
-- | Compute a runtime witness of m - n, or Nothing.
trySub :: (SNumberRepr a, OverflowArith a) => SNumber a m -> SNumber a n -> Maybe (SNumber a (m - n))
-- | Compute a runtime witness of m * n, or Nothing.
tryMul :: (SNumberRepr a, OverflowArith a) => SNumber a m -> SNumber a n -> Maybe (SNumber a (m * n))
-- | An exception for overflows in checked SNumber arithmetic.
data UnrepresentableSNumber
UnrepresentableSNumber :: String -> Integer -> Integer -> UnrepresentableSNumber
-- | Compute a runtime witness of m + n, or throw.
chkAdd :: (SNumberRepr a, OverflowArith a, HasCallStack) => SNumber a m -> SNumber a n -> SNumber a (m + n)
-- | Compute a runtime witness of m - n, or throw.
chkSub :: (SNumberRepr a, OverflowArith a, HasCallStack) => SNumber a m -> SNumber a n -> SNumber a (m - n)
-- | Compute a runtime witness of m * n, or throw.
chkMul :: (SNumberRepr a, OverflowArith a, HasCallStack) => SNumber a m -> SNumber a n -> SNumber a (m * n)
-- | Compute a runtime witness of exact division.
--
-- We could provide division in terms of Div instead, but
-- Kinds.Integer doesn't currently have division.
divExact :: SNumberRepr a => SNumber a (m * n) -> SNumber a n -> SNumber a m
-- | Like KnownNat, but represented by a instead of
-- Natural.
--
-- This is currently solved automatically from KnownNat via
-- runtime checks, to ease migration (we can incrementally strengthen
-- KnownNat constraints to KnownSNumber constraints), but
-- in the future it may be changed to use SafeSNumber, which will
-- rule out runtime failures but will require additional proofs in order
-- to solve via KnownNat. For statically known Integers,
-- these proofs will be entirely automatic.
--
-- This class is meant to be used primarily in instance contexts; for
-- standalone functions, it's probably better to pass an SNumber
-- explicitly.
class KnownSNumber a n
-- | Implementation of snumberVal.
--
-- This has an inconvenient type variable order because it derives from
-- the order they appear in the class head; see snumberVal.
snumberVal_ :: KnownSNumber a n => SNumber a n
-- | Implementation of snumberVal.
--
-- This has an inconvenient type variable order because it derives from
-- the order they appear in the class head; see snumberVal.
snumberVal_ :: (KnownSNumber a n, SNumberRepr a, KnownInteger n) => SNumber a n
-- | Get an SNumber out of the context from KnownSNumber or
-- KnownNat.
--
-- This has the number as its first type parameter, for TypeApplications
-- convenience.
snumberVal :: forall n a. KnownSNumber a n => SNumber a n
-- | Stash an SNumber at the type level as a KnownSNumber
-- instance.
reifySNumber :: forall a n r. SNumber a n -> (KnownSNumber a n => r) -> r
-- | Use a positive SNumber to introduce a KnownNat instance.
reifySNumberAsNat :: forall n r a. Integral a => SNumber a ('Pos n) -> (KnownNat n => r) -> r
-- | The number of bits in the present system's Int type.
type IntBits = 64
-- | The smallest representable Int value.
type IntMin = 'Neg (2 ^ (IntBits - 1))
-- | One more than the largest representable Int value.
type IntMaxP1 = 'Pos (2 ^ (IntBits - 1))
-- | The number of bits in the present system's Word type.
type WordBits = 64
-- | One more than the largest representable Word value.
type WordMaxP1 = 'Pos (2 ^ WordBits)
instance GHC.Show.Show a => GHC.Show.Show (Data.SNumber.SNumber a n)
instance GHC.Show.Show Data.SNumber.UnrepresentableSNumber
instance GHC.Exception.Type.Exception Data.SNumber.UnrepresentableSNumber
instance Data.SNumber.OverflowArith GHC.Types.Word
instance Data.SNumber.OverflowArith GHC.Types.Int
instance Data.SNumber.OverflowArith GHC.Natural.Natural
instance Data.SNumber.OverflowArith GHC.Integer.Type.Integer
instance (Data.SNumber.SNumberRepr a, Kinds.Integer.KnownInteger n) => Data.SNumber.KnownSNumber a n
instance Data.SNumber.SNumberRepr GHC.Types.Int
instance Data.SNumber.SNumberRepr GHC.Types.Word
instance Data.SNumber.SNumberRepr GHC.Integer.Type.Integer
instance Data.SNumber.SNumberRepr GHC.Natural.Natural
instance (Data.SNumber.Internal.IsAtLeastMinBound ('Kinds.Integer.Neg (2 GHC.TypeNats.^ (w Kinds.Num.- 1))) (Data.SNumber.SignedReprRangeErr w repr a) n, Data.SNumber.Internal.IsLessThanMaxBound ('Kinds.Integer.Pos (2 GHC.TypeNats.^ (w Kinds.Num.- 1))) (Data.SNumber.SignedReprRangeErr w repr a) n, Data.SNumber.Internal.ForbidNegZero n) => Data.SNumber.LitIsSignedBits w repr a n
instance (Data.SNumber.Internal.IsAtLeastMinBound ('Kinds.Integer.Pos 0) (Data.SNumber.Internal.NegativeReprUnsignedErr repr a) n, Data.SNumber.Internal.IsLessThanMaxBound ('Kinds.Integer.Pos (2 GHC.TypeNats.^ w)) (Data.SNumber.Internal.OutOfReprRangeErr ('Kinds.Integer.Pos 0) ('Kinds.Integer.Pos (2 GHC.TypeNats.^ w)) repr a) n, Data.SNumber.Internal.ForbidNegZero n) => Data.SNumber.LitIsUnsignedBits w repr a n
instance Data.SNumber.Internal.ForbidNegZero n => Data.SNumber.LitIsAnything n