-- 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.2.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: -- -- -- -- 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 -- -- -- -- 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 -- | Ordering results carrying evidence of type-level ordering relations. data SOrdering m n [SLT] :: CmpInteger m n ~ 'LT => SOrdering m n -- | This doesn't currently prove m ~ n, but since we've forbidden SNumbers -- of 'Neg 0, it probably could. [SEQ] :: CmpInteger m n ~ 'EQ => SOrdering m n [SGT] :: CmpInteger m n ~ 'GT => SOrdering m n -- | Compare two type-level Integers using their runtime witnesses. compareSNumber :: forall m n a. Ord a => SNumber a m -> SNumber a n -> SOrdering 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: -- -- -- -- 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)) 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. 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. 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