2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
4 \section[PrelBounded]{Module @PrelBounded@}
6 Instances of Bounded for various datatypes.
9 {-# OPTIONS -fno-implicit-prelude #-}
12 Bounded(..), Enum(..),
13 enumFromBounded, enumFromThenBounded,
15 -- Instances for Bounded and Eum: (), Char, Int
19 import {-# SOURCE #-} PrelErr ( error )
21 import PrelTup () -- To make sure we look for the .hi file
23 default () -- Double isn't available yet
27 %*********************************************************
29 \subsection{Class declarations}
31 %*********************************************************
35 minBound, maxBound :: a
41 enumFrom :: a -> [a] -- [n..]
42 enumFromThen :: a -> a -> [a] -- [n,n'..]
43 enumFromTo :: a -> a -> [a] -- [n..m]
44 enumFromThenTo :: a -> a -> a -> [a] -- [n,n'..m]
46 succ = toEnum . (`plusInt` oneInt) . fromEnum
47 pred = toEnum . (`minusInt` oneInt) . fromEnum
48 enumFrom x = map toEnum [fromEnum x ..]
49 enumFromThen x y = map toEnum [fromEnum x, fromEnum y ..]
50 enumFromTo x y = map toEnum [fromEnum x .. fromEnum y]
51 enumFromThenTo x1 x2 y = map toEnum [fromEnum x1, fromEnum x2 .. fromEnum y]
53 -- Default methods for bounded enumerations
54 enumFromBounded :: (Enum a, Bounded a) => a -> [a]
55 enumFromBounded n = map toEnum [fromEnum n .. fromEnum (maxBound `asTypeOf` n)]
57 enumFromThenBounded :: (Enum a, Bounded a) => a -> a -> [a]
58 enumFromThenBounded n1 n2
59 | i_n2 >= i_n1 = map toEnum [i_n1, i_n2 .. fromEnum (maxBound `asTypeOf` n1)]
60 | otherwise = map toEnum [i_n1, i_n2 .. fromEnum (minBound `asTypeOf` n1)]
67 %*********************************************************
71 %*********************************************************
74 instance Bounded () where
78 instance Enum () where
79 succ _ = error "Prelude.Enum.().succ: bad argment"
80 pred _ = error "Prelude.Enum.().pred: bad argument"
82 toEnum x | x == zeroInt = ()
83 | otherwise = error "Prelude.Enum.().toEnum: bad argument"
87 enumFromThen () () = [()]
88 enumFromTo () () = [()]
89 enumFromThenTo () () () = [()]
93 instance (Bounded a, Bounded b) => Bounded (a,b) where
94 minBound = (minBound, minBound)
95 maxBound = (maxBound, maxBound)
97 instance (Bounded a, Bounded b, Bounded c) => Bounded (a,b,c) where
98 minBound = (minBound, minBound, minBound)
99 maxBound = (maxBound, maxBound, maxBound)
101 instance (Bounded a, Bounded b, Bounded c, Bounded d) => Bounded (a,b,c,d) where
102 minBound = (minBound, minBound, minBound, minBound)
103 maxBound = (maxBound, maxBound, maxBound, maxBound)
107 %*********************************************************
109 \subsection{Type @Bool@}
111 %*********************************************************
114 instance Bounded Bool where
118 instance Enum Bool where
120 succ True = error "Prelude.Enum.Bool.succ: bad argment"
123 pred False = error "Prelude.Enum.Bool.pred: bad argment"
125 toEnum n | n == zeroInt = False
127 | otherwise = error "Prelude.Enum.Bool.toEnum: bad argment"
129 fromEnum False = zeroInt
130 fromEnum True = oneInt
132 -- Use defaults for the rest
133 enumFrom = enumFromBounded
134 enumFromThen = enumFromThenBounded
137 %*********************************************************
139 \subsection{Type @Ordering@}
141 %*********************************************************
144 instance Bounded Ordering where
148 instance Enum Ordering where
151 succ GT = error "Prelude.Enum.Ordering.succ: bad argment"
155 pred LT = error "Prelude.Enum.Ordering.pred: bad argment"
157 toEnum n | n == zeroInt = LT
160 toEnum _ = error "Prelude.Enum.Ordering.toEnum: bad argment"
162 fromEnum LT = zeroInt
166 -- Use defaults for the rest
167 enumFrom = enumFromBounded
168 enumFromThen = enumFromThenBounded
171 %*********************************************************
173 \subsection{Type @Char@}
175 %*********************************************************
178 instance Bounded Char where
182 instance Enum Char where
184 | not (ord# c# ==# 255#) = C# (chr# (ord# c# +# 1#))
185 | otherwise = error ("Prelude.Enum.Char.succ: bad argument")
187 | not (ord# c# ==# 0#) = C# (chr# (ord# c# -# 1#))
188 | otherwise = error ("Prelude.Enum.Char.pred: bad argument")
193 {-# INLINE enumFrom #-}
194 enumFrom (C# x) = eftChar (ord# x) 255#
195 -- Blarg: technically I guess enumFrom isn't strict!
197 {-# INLINE enumFromTo #-}
198 enumFromTo (C# x) (C# y) = eftChar (ord# x) (ord# y)
200 {-# INLINE enumFromThen #-}
201 enumFromThen (C# x1) (C# x2) = efdChar (ord# x1) (ord# x2)
203 {-# INLINE enumFromThenTo #-}
204 enumFromThenTo (C# x1) (C# x2) (C# y) = efdtChar (ord# x1) (ord# x2) (ord# y)
206 eftChar = eftCharList
207 efdChar = efdCharList
208 efdtChar = efdtCharList
212 "eftChar" forall x y. eftChar x y = build (\c n -> eftCharFB c n x y)
213 "efdChar" forall x1 x2. efdChar x1 x2 = build (\ c n -> efdCharFB c n x1 x2)
214 "efdtChar" forall x1 x2 l. efdtChar x1 x2 l = build (\ c n -> efdtCharFB c n x1 x2 l)
215 "eftCharList" eftCharFB (:) [] = eftCharList
216 "efdCharList" efdCharFB (:) [] = efdCharList
217 "efdtCharList" efdtCharFB (:) [] = efdtCharList
221 -- We can do better than for Ints because we don't
222 -- have hassles about arithmetic overflow at maxBound
223 {-# INLINE eftCharFB #-}
224 eftCharFB c n x y = go x
227 | otherwise = C# (chr# x) `c` go (x +# 1#)
229 eftCharList x y | x ># y = []
230 | otherwise = C# (chr# x) : eftCharList (x +# 1#) y
233 -- For enumFromThenTo we give up on inlining
235 | delta >=# 0# = go_up_char_fb c n x1 delta 255#
236 | otherwise = go_dn_char_fb c n x1 delta 0#
241 | delta >=# 0# = go_up_char_list x1 delta 255#
242 | otherwise = go_dn_char_list x1 delta 0#
246 efdtCharFB c n x1 x2 lim
247 | delta >=# 0# = go_up_char_fb c n x1 delta lim
248 | otherwise = go_dn_char_fb c n x1 delta lim
252 efdtCharList x1 x2 lim
253 | delta >=# 0# = go_up_char_list x1 delta lim
254 | otherwise = go_dn_char_list x1 delta lim
258 go_up_char_fb c n x delta lim
261 go_up x | x ># lim = n
262 | otherwise = C# (chr# x) `c` go_up (x +# delta)
264 go_dn_char_fb c n x delta lim
267 go_dn x | x <# lim = n
268 | otherwise = C# (chr# x) `c` go_dn (x +# delta)
270 go_up_char_list x delta lim
273 go_up x | x ># lim = []
274 | otherwise = C# (chr# x) : go_up (x +# delta)
276 go_dn_char_list x delta lim
279 go_dn x | x <# lim = []
280 | otherwise = C# (chr# x) : go_dn (x +# delta)
284 %*********************************************************
286 \subsection{Type @Int@}
288 %*********************************************************
290 Be careful about these instances.
291 (a) remember that you have to count down as well as up e.g. [13,12..0]
292 (b) be careful of Int overflow
293 (c) remember that Int is bounded, so [1..] terminates at maxInt
295 Also NB that the Num class isn't available in this module.
298 instance Bounded Int where
302 instance Enum Int where
304 | x == maxBound = error "Prelude.Enum.succ{Int}: tried to take `succ' of maxBound"
305 | otherwise = x `plusInt` oneInt
307 | x == minBound = error "Prelude.Enum.pred{Int}: tried to take `pred' of minBound"
308 | otherwise = x `minusInt` oneInt
313 {-# INLINE enumFrom #-}
314 enumFrom (I# x) = eftInt x 2147483647#
315 -- Blarg: technically I guess enumFrom isn't strict!
317 {-# INLINE enumFromTo #-}
318 enumFromTo (I# x) (I# y) = eftInt x y
320 {-# INLINE enumFromThen #-}
321 enumFromThen (I# x1) (I# x2) = efdInt x1 x2
323 {-# INLINE enumFromThenTo #-}
324 enumFromThenTo (I# x1) (I# x2) (I# y) = efdtInt x1 x2 y
328 efdtInt = efdtIntList
331 "eftInt" forall x y. eftInt x y = build (\ c n -> eftIntFB c n x y)
332 "efdInt" forall x1 x2. efdInt x1 x2 = build (\ c n -> efdIntFB c n x1 x2)
333 "efdtInt" forall x1 x2 l. efdtInt x1 x2 l = build (\ c n -> efdtIntFB c n x1 x2 l)
335 "eftIntList" eftIntFB (:) [] = eftIntList
336 "efdIntList" efdIntFB (:) [] = efdIntList
337 "efdtIntList" efdtIntFB (:) [] = efdtIntList
341 {-# INLINE eftIntFB #-}
342 eftIntFB c n x y | x ># y = n
345 go x = I# x `c` if x ==# y then n else go (x +# 1#)
346 -- Watch out for y=maxBound; hence ==, not >
347 -- Be very careful not to have more than one "c"
348 -- so that when eftInfFB is inlined we can inline
349 -- whatver is bound to "c"
351 eftIntList x y | x ># y = []
354 go x = I# x : if x ==# y then [] else go (x +# 1#)
357 -- For enumFromThenTo we give up on inlining; so we don't worry
358 -- about duplicating occurrences of "c"
359 efdtIntFB c n x1 x2 y
360 | delta >=# 0# = if x1 ># y then n else go_up_int_fb c n x1 delta lim
361 | otherwise = if x1 <# y then n else go_dn_int_fb c n x1 delta lim
367 | delta >=# 0# = if x1 ># y then [] else go_up_int_list x1 delta lim
368 | otherwise = if x1 <# y then [] else go_dn_int_list x1 delta lim
374 | delta >=# 0# = go_up_int_fb c n x1 delta ( 2147483647# -# delta)
375 | otherwise = go_dn_int_fb c n x1 delta ((-2147483648#) -# delta)
380 | delta >=# 0# = go_up_int_list x1 delta ( 2147483647# -# delta)
381 | otherwise = go_dn_int_list x1 delta ((-2147483648#) -# delta)
385 -- In all of these, the (x +# delta) is guaranteed not to overflow
387 go_up_int_fb c n x delta lim
390 go_up x | x ># lim = I# x `c` n
391 | otherwise = I# x `c` go_up (x +# delta)
393 go_dn_int_fb c n x delta lim
396 go_dn x | x <# lim = I# x `c` n
397 | otherwise = I# x `c` go_dn (x +# delta)
399 go_up_int_list x delta lim
402 go_up x | x ># lim = [I# x]
403 | otherwise = I# x : go_up (x +# delta)
405 go_dn_int_list x delta lim
408 go_dn x | x <# lim = [I# x]
409 | otherwise = I# x : go_dn (x +# delta)