@@ -92,42 +92,46 @@ import Data.Proxy
9292import GHC.TypeLits
9393
9494-- | Wrapper around 'Int's that have a restrictive semantic associated.
95−-- A value of type @'Natural' n@ can only be instanciated with some 'Int'
96−-- @i@ that's @0 <= i <= n@.
97−newtype Natural (nat :: Nat) = Nat Int
95+-- A value of type @'Natural' n m@ can only be instanciated with some 'Int'
96+-- @i@ that's @n <= i <= m@.
97+newtype Natural (start :: Nat) (end :: Nat) = Nat Int
9898 deriving (Show, Read, Eq, Num)
9999
100100-- | Natural constructor function. Throws a runtime error if the 'Int'
101−-- value is greater than the corresponding @n@ in the @'Natural' n@ type.
102−nat :: forall n. (KnownNat n) => Int -> Natural n
101+-- value is greater than the corresponding @m@ or lower than @n@ in the @'Natural' n m@ type.
102+nat :: forall n m . (KnownNat n, KnownNat m) => Int -> Natural n m
103103nat i =
104− let nat = fromInteger (natVal (Proxy :: Proxy n))
105− in if i <= nat
104+ let start = fromInteger (natVal (Proxy :: Proxy n))
105+ end = fromInteger (natVal (Proxy :: Proxy m))
106+ in if start <= i && i <= end
106107 then Nat i
107108 else error "Off limits"
108109
109110-- | Auxiliary function that promotes binary 'Int' functions to 'Natural'
110111-- binary functions.
111−coerceNat :: (Int -> Int -> Int) -> (Natural a -> Natural b -> Natural c)
112+coerceNat :: (Int -> Int -> Int) -> (Natural a a' -> Natural b b' -> Natural c c')
112113coerceNat = coerce
113114
114115-- | Auxiliary function that promotes ternary (binary) 'Int' functions to 'Natural'
115116-- functions.
116−coerceNat2 :: ((Int, Int) -> Int -> Int) -> ((Natural a, Natural b) -> Natural c -> Natural d)
117+coerceNat2 :: ((Int, Int) -> Int -> Int) -> ((Natural a a', Natural b b') -> Natural c c' -> Natural d d')
117118coerceNat2 = coerce
118119
119−instance KnownNat n => Bounded (Natural n) where
120− minBound = Nat 0
121− maxBound = Nat $ fromInteger (natVal (Proxy :: Proxy n))
120+instance (KnownNat n, KnownNat m) => Bounded (Natural n m) where
121+ minBound = Nat $ fromInteger (natVal (Proxy :: Proxy n))
122+ maxBound = Nat $ fromInteger (natVal (Proxy :: Proxy m))
122123
123−instance KnownNat n => Enum (Natural n) where
124− toEnum = nat
124+instance (KnownNat n, KnownNat m) => Enum (Natural n m) where
125+ toEnum i =
126+ let start = fromInteger (natVal (Proxy :: Proxy n))
127+ in nat (start + i)
125128 -- | Throws a runtime error if the value is off limits
126129 fromEnum (Nat nat) =
127− let val = fromInteger (natVal (Proxy :: Proxy n))
128− in if nat > val
129− then error "Off limits"
130− else nat
130+ let start = fromInteger (natVal (Proxy :: Proxy n))
131+ end = fromInteger (natVal (Proxy :: Proxy m))
132+ in if start <= nat && nat <= end
133+ then nat - start
134+ else error "Off limits"
131135
132136-- | Optimized 'Enum' instance for tuples that comply with the given
133137-- constraints.