1 % -----------------------------------------------------------------------------
2 % $Id: PrelEnum.lhs,v 1.11 2000/06/30 13:39:35 simonmar Exp $
4 % (c) The University of Glasgow, 1992-2000
7 \section[PrelBounded]{Module @PrelBounded@}
9 Instances of Bounded for various datatypes.
12 {-# OPTIONS -fno-implicit-prelude #-}
15 Bounded(..), Enum(..),
16 boundedEnumFrom, boundedEnumFromThen,
18 -- Instances for Bounded and Eum: (), Char, Int
22 import {-# SOURCE #-} PrelErr ( error )
24 import PrelTup () -- To make sure we look for the .hi file
26 default () -- Double isn't available yet
30 %*********************************************************
32 \subsection{Class declarations}
34 %*********************************************************
38 minBound, maxBound :: a
44 enumFrom :: a -> [a] -- [n..]
45 enumFromThen :: a -> a -> [a] -- [n,n'..]
46 enumFromTo :: a -> a -> [a] -- [n..m]
47 enumFromThenTo :: a -> a -> a -> [a] -- [n,n'..m]
49 succ = toEnum . (`plusInt` oneInt) . fromEnum
50 pred = toEnum . (`minusInt` oneInt) . fromEnum
51 enumFrom x = map toEnum [fromEnum x ..]
52 enumFromThen x y = map toEnum [fromEnum x, fromEnum y ..]
53 enumFromTo x y = map toEnum [fromEnum x .. fromEnum y]
54 enumFromThenTo x1 x2 y = map toEnum [fromEnum x1, fromEnum x2 .. fromEnum y]
56 -- Default methods for bounded enumerations
57 boundedEnumFrom :: (Enum a, Bounded a) => a -> [a]
58 boundedEnumFrom n = map toEnum [fromEnum n .. fromEnum (maxBound `asTypeOf` n)]
60 boundedEnumFromThen :: (Enum a, Bounded a) => a -> a -> [a]
61 boundedEnumFromThen n1 n2
62 | i_n2 >= i_n1 = map toEnum [i_n1, i_n2 .. fromEnum (maxBound `asTypeOf` n1)]
63 | otherwise = map toEnum [i_n1, i_n2 .. fromEnum (minBound `asTypeOf` n1)]
70 %*********************************************************
74 %*********************************************************
77 instance Bounded () where
81 instance Enum () where
82 succ _ = error "Prelude.Enum.().succ: bad argment"
83 pred _ = error "Prelude.Enum.().pred: bad argument"
85 toEnum x | x == zeroInt = ()
86 | otherwise = error "Prelude.Enum.().toEnum: bad argument"
90 enumFromThen () () = [()]
91 enumFromTo () () = [()]
92 enumFromThenTo () () () = [()]
96 instance (Bounded a, Bounded b) => Bounded (a,b) where
97 minBound = (minBound, minBound)
98 maxBound = (maxBound, maxBound)
100 instance (Bounded a, Bounded b, Bounded c) => Bounded (a,b,c) where
101 minBound = (minBound, minBound, minBound)
102 maxBound = (maxBound, maxBound, maxBound)
104 instance (Bounded a, Bounded b, Bounded c, Bounded d) => Bounded (a,b,c,d) where
105 minBound = (minBound, minBound, minBound, minBound)
106 maxBound = (maxBound, maxBound, maxBound, maxBound)
110 %*********************************************************
112 \subsection{Type @Bool@}
114 %*********************************************************
117 instance Bounded Bool where
121 instance Enum Bool where
123 succ True = error "Prelude.Enum.Bool.succ: bad argment"
126 pred False = error "Prelude.Enum.Bool.pred: bad argment"
128 toEnum n | n == zeroInt = False
130 | otherwise = error "Prelude.Enum.Bool.toEnum: bad argment"
132 fromEnum False = zeroInt
133 fromEnum True = oneInt
135 -- Use defaults for the rest
136 enumFrom = boundedEnumFrom
137 enumFromThen = boundedEnumFromThen
140 %*********************************************************
142 \subsection{Type @Ordering@}
144 %*********************************************************
147 instance Bounded Ordering where
151 instance Enum Ordering where
154 succ GT = error "Prelude.Enum.Ordering.succ: bad argment"
158 pred LT = error "Prelude.Enum.Ordering.pred: bad argment"
160 toEnum n | n == zeroInt = LT
163 toEnum _ = error "Prelude.Enum.Ordering.toEnum: bad argment"
165 fromEnum LT = zeroInt
169 -- Use defaults for the rest
170 enumFrom = boundedEnumFrom
171 enumFromThen = boundedEnumFromThen
174 %*********************************************************
176 \subsection{Type @Char@}
178 %*********************************************************
181 instance Bounded Char where
185 instance Enum Char where
187 | not (ord# c# ==# 255#) = C# (chr# (ord# c# +# 1#))
188 | otherwise = error ("Prelude.Enum.Char.succ: bad argument")
190 | not (ord# c# ==# 0#) = C# (chr# (ord# c# -# 1#))
191 | otherwise = error ("Prelude.Enum.Char.pred: bad argument")
196 {-# INLINE enumFrom #-}
197 enumFrom (C# x) = eftChar (ord# x) 255#
198 -- Blarg: technically I guess enumFrom isn't strict!
200 {-# INLINE enumFromTo #-}
201 enumFromTo (C# x) (C# y) = eftChar (ord# x) (ord# y)
203 {-# INLINE enumFromThen #-}
204 enumFromThen (C# x1) (C# x2) = efdChar (ord# x1) (ord# x2)
206 {-# INLINE enumFromThenTo #-}
207 enumFromThenTo (C# x1) (C# x2) (C# y) = efdtChar (ord# x1) (ord# x2) (ord# y)
209 eftChar = eftCharList
210 efdChar = efdCharList
211 efdtChar = efdtCharList
215 "eftChar" forall x y. eftChar x y = build (\c n -> eftCharFB c n x y)
216 "efdChar" forall x1 x2. efdChar x1 x2 = build (\ c n -> efdCharFB c n x1 x2)
217 "efdtChar" forall x1 x2 l. efdtChar x1 x2 l = build (\ c n -> efdtCharFB c n x1 x2 l)
218 "eftCharList" eftCharFB (:) [] = eftCharList
219 "efdCharList" efdCharFB (:) [] = efdCharList
220 "efdtCharList" efdtCharFB (:) [] = efdtCharList
224 -- We can do better than for Ints because we don't
225 -- have hassles about arithmetic overflow at maxBound
226 {-# INLINE eftCharFB #-}
227 eftCharFB c n x y = go x
230 | otherwise = C# (chr# x) `c` go (x +# 1#)
232 eftCharList x y | x ># y = []
233 | otherwise = C# (chr# x) : eftCharList (x +# 1#) y
236 -- For enumFromThenTo we give up on inlining
238 | delta >=# 0# = go_up_char_fb c n x1 delta 255#
239 | otherwise = go_dn_char_fb c n x1 delta 0#
244 | delta >=# 0# = go_up_char_list x1 delta 255#
245 | otherwise = go_dn_char_list x1 delta 0#
249 efdtCharFB c n x1 x2 lim
250 | delta >=# 0# = go_up_char_fb c n x1 delta lim
251 | otherwise = go_dn_char_fb c n x1 delta lim
255 efdtCharList x1 x2 lim
256 | delta >=# 0# = go_up_char_list x1 delta lim
257 | otherwise = go_dn_char_list x1 delta lim
261 go_up_char_fb c n x delta lim
264 go_up x | x ># lim = n
265 | otherwise = C# (chr# x) `c` go_up (x +# delta)
267 go_dn_char_fb c n x delta lim
270 go_dn x | x <# lim = n
271 | otherwise = C# (chr# x) `c` go_dn (x +# delta)
273 go_up_char_list x delta lim
276 go_up x | x ># lim = []
277 | otherwise = C# (chr# x) : go_up (x +# delta)
279 go_dn_char_list x delta lim
282 go_dn x | x <# lim = []
283 | otherwise = C# (chr# x) : go_dn (x +# delta)
287 %*********************************************************
289 \subsection{Type @Int@}
291 %*********************************************************
293 Be careful about these instances.
294 (a) remember that you have to count down as well as up e.g. [13,12..0]
295 (b) be careful of Int overflow
296 (c) remember that Int is bounded, so [1..] terminates at maxInt
298 Also NB that the Num class isn't available in this module.
301 instance Bounded Int where
305 instance Enum Int where
307 | x == maxBound = error "Prelude.Enum.succ{Int}: tried to take `succ' of maxBound"
308 | otherwise = x `plusInt` oneInt
310 | x == minBound = error "Prelude.Enum.pred{Int}: tried to take `pred' of minBound"
311 | otherwise = x `minusInt` oneInt
316 {-# INLINE enumFrom #-}
317 enumFrom (I# x) = eftInt x 2147483647#
318 -- Blarg: technically I guess enumFrom isn't strict!
320 {-# INLINE enumFromTo #-}
321 enumFromTo (I# x) (I# y) = eftInt x y
323 {-# INLINE enumFromThen #-}
324 enumFromThen (I# x1) (I# x2) = efdInt x1 x2
326 {-# INLINE enumFromThenTo #-}
327 enumFromThenTo (I# x1) (I# x2) (I# y) = efdtInt x1 x2 y
331 efdtInt = efdtIntList
334 "eftInt" forall x y. eftInt x y = build (\ c n -> eftIntFB c n x y)
335 "efdInt" forall x1 x2. efdInt x1 x2 = build (\ c n -> efdIntFB c n x1 x2)
336 "efdtInt" forall x1 x2 l. efdtInt x1 x2 l = build (\ c n -> efdtIntFB c n x1 x2 l)
338 "eftIntList" eftIntFB (:) [] = eftIntList
339 "efdIntList" efdIntFB (:) [] = efdIntList
340 "efdtIntList" efdtIntFB (:) [] = efdtIntList
344 {-# INLINE eftIntFB #-}
345 eftIntFB c n x y | x ># y = n
348 go x = I# x `c` if x ==# y then n else go (x +# 1#)
349 -- Watch out for y=maxBound; hence ==, not >
350 -- Be very careful not to have more than one "c"
351 -- so that when eftInfFB is inlined we can inline
352 -- whatver is bound to "c"
354 eftIntList x y | x ># y = []
357 go x = I# x : if x ==# y then [] else go (x +# 1#)
360 -- For enumFromThenTo we give up on inlining; so we don't worry
361 -- about duplicating occurrences of "c"
362 efdtIntFB c n x1 x2 y
363 | delta >=# 0# = if x1 ># y then n else go_up_int_fb c n x1 delta lim
364 | otherwise = if x1 <# y then n else go_dn_int_fb c n x1 delta lim
370 | delta >=# 0# = if x1 ># y then [] else go_up_int_list x1 delta lim
371 | otherwise = if x1 <# y then [] else go_dn_int_list x1 delta lim
377 | delta >=# 0# = go_up_int_fb c n x1 delta ( 2147483647# -# delta)
378 | otherwise = go_dn_int_fb c n x1 delta ((-2147483648#) -# delta)
383 | delta >=# 0# = go_up_int_list x1 delta ( 2147483647# -# delta)
384 | otherwise = go_dn_int_list x1 delta ((-2147483648#) -# delta)
388 -- In all of these, the (x +# delta) is guaranteed not to overflow
390 go_up_int_fb c n x delta lim
393 go_up x | x ># lim = I# x `c` n
394 | otherwise = I# x `c` go_up (x +# delta)
396 go_dn_int_fb c n x delta lim
399 go_dn x | x <# lim = I# x `c` n
400 | otherwise = I# x `c` go_dn (x +# delta)
402 go_up_int_list x delta lim
405 go_up x | x ># lim = [I# x]
406 | otherwise = I# x : go_up (x +# delta)
408 go_dn_int_list x delta lim
411 go_dn x | x <# lim = [I# x]
412 | otherwise = I# x : go_dn (x +# delta)