1 % -----------------------------------------------------------------------------
2 % $Id: PrelEnum.lhs,v 1.17 2001/09/26 15:12:37 simonpj Exp $
4 % (c) The University of Glasgow, 1992-2001
7 Instances of Bounded and Enum for various datatypes.
10 {-# OPTIONS -fno-implicit-prelude #-}
13 Bounded(..), Enum(..),
14 boundedEnumFrom, boundedEnumFromThen,
16 -- Instances for Bounded and Eum: (), Char, Int
20 import {-# SOURCE #-} PrelErr ( error )
22 import PrelTup () -- To make sure we look for the .hi file
24 default () -- Double isn't available yet
28 %*********************************************************
30 \subsection{Class declarations}
32 %*********************************************************
36 minBound, maxBound :: a
42 enumFrom :: a -> [a] -- [n..]
43 enumFromThen :: a -> a -> [a] -- [n,n'..]
44 enumFromTo :: a -> a -> [a] -- [n..m]
45 enumFromThenTo :: a -> a -> a -> [a] -- [n,n'..m]
47 succ = toEnum . (`plusInt` oneInt) . fromEnum
48 pred = toEnum . (`minusInt` oneInt) . fromEnum
49 enumFrom x = map toEnum [fromEnum x ..]
50 enumFromThen x y = map toEnum [fromEnum x, fromEnum y ..]
51 enumFromTo x y = map toEnum [fromEnum x .. fromEnum y]
52 enumFromThenTo x1 x2 y = map toEnum [fromEnum x1, fromEnum x2 .. fromEnum y]
54 -- Default methods for bounded enumerations
55 boundedEnumFrom :: (Enum a, Bounded a) => a -> [a]
56 boundedEnumFrom n = map toEnum [fromEnum n .. fromEnum (maxBound `asTypeOf` n)]
58 boundedEnumFromThen :: (Enum a, Bounded a) => a -> a -> [a]
59 boundedEnumFromThen n1 n2
60 | i_n2 >= i_n1 = map toEnum [i_n1, i_n2 .. fromEnum (maxBound `asTypeOf` n1)]
61 | otherwise = map toEnum [i_n1, i_n2 .. fromEnum (minBound `asTypeOf` n1)]
68 %*********************************************************
72 %*********************************************************
75 instance Bounded () where
79 instance Enum () where
80 succ _ = error "Prelude.Enum.().succ: bad argment"
81 pred _ = error "Prelude.Enum.().pred: bad argument"
83 toEnum x | x == zeroInt = ()
84 | otherwise = error "Prelude.Enum.().toEnum: bad argument"
88 enumFromThen () () = [()]
89 enumFromTo () () = [()]
90 enumFromThenTo () () () = [()]
94 instance (Bounded a, Bounded b) => Bounded (a,b) where
95 minBound = (minBound, minBound)
96 maxBound = (maxBound, maxBound)
98 instance (Bounded a, Bounded b, Bounded c) => Bounded (a,b,c) where
99 minBound = (minBound, minBound, minBound)
100 maxBound = (maxBound, maxBound, maxBound)
102 instance (Bounded a, Bounded b, Bounded c, Bounded d) => Bounded (a,b,c,d) where
103 minBound = (minBound, minBound, minBound, minBound)
104 maxBound = (maxBound, maxBound, maxBound, maxBound)
108 %*********************************************************
110 \subsection{Type @Bool@}
112 %*********************************************************
115 instance Bounded Bool where
119 instance Enum Bool where
121 succ True = error "Prelude.Enum.Bool.succ: bad argment"
124 pred False = error "Prelude.Enum.Bool.pred: bad argment"
126 toEnum n | n == zeroInt = False
128 | otherwise = error "Prelude.Enum.Bool.toEnum: bad argment"
130 fromEnum False = zeroInt
131 fromEnum True = oneInt
133 -- Use defaults for the rest
134 enumFrom = boundedEnumFrom
135 enumFromThen = boundedEnumFromThen
138 %*********************************************************
140 \subsection{Type @Ordering@}
142 %*********************************************************
145 instance Bounded Ordering where
149 instance Enum Ordering where
152 succ GT = error "Prelude.Enum.Ordering.succ: bad argment"
156 pred LT = error "Prelude.Enum.Ordering.pred: bad argment"
158 toEnum n | n == zeroInt = LT
161 toEnum _ = error "Prelude.Enum.Ordering.toEnum: bad argment"
163 fromEnum LT = zeroInt
167 -- Use defaults for the rest
168 enumFrom = boundedEnumFrom
169 enumFromThen = boundedEnumFromThen
172 %*********************************************************
174 \subsection{Type @Char@}
176 %*********************************************************
179 instance Bounded Char where
181 maxBound = '\x10FFFF'
183 instance Enum Char where
185 | not (ord# c# ==# 0x10FFFF#) = C# (chr# (ord# c# +# 1#))
186 | otherwise = error ("Prelude.Enum.Char.succ: bad argument")
188 | not (ord# c# ==# 0#) = C# (chr# (ord# c# -# 1#))
189 | otherwise = error ("Prelude.Enum.Char.pred: bad argument")
194 {-# INLINE enumFrom #-}
195 enumFrom (C# x) = eftChar (ord# x) 0x10FFFF#
196 -- Blarg: technically I guess enumFrom isn't strict!
198 {-# INLINE enumFromTo #-}
199 enumFromTo (C# x) (C# y) = eftChar (ord# x) (ord# y)
201 {-# INLINE enumFromThen #-}
202 enumFromThen (C# x1) (C# x2) = efdChar (ord# x1) (ord# x2)
204 {-# INLINE enumFromThenTo #-}
205 enumFromThenTo (C# x1) (C# x2) (C# y) = efdtChar (ord# x1) (ord# x2) (ord# y)
207 {-# NOINLINE [1] eftChar #-}
208 {-# NOINLINE [1] efdChar #-}
209 {-# NOINLINE [1] efdtChar #-}
210 eftChar = eftCharList
211 efdChar = efdCharList
212 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 [0] 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
237 {-# NOINLINE [0] efdCharFB #-}
239 | delta >=# 0# = go_up_char_fb c n x1 delta 0x10FFFF#
240 | otherwise = go_dn_char_fb c n x1 delta 0#
245 | delta >=# 0# = go_up_char_list x1 delta 0x10FFFF#
246 | otherwise = go_dn_char_list x1 delta 0#
250 {-# NOINLINE [0] efdtCharFB #-}
251 efdtCharFB c n x1 x2 lim
252 | delta >=# 0# = go_up_char_fb c n x1 delta lim
253 | otherwise = go_dn_char_fb c n x1 delta lim
257 efdtCharList x1 x2 lim
258 | delta >=# 0# = go_up_char_list x1 delta lim
259 | otherwise = go_dn_char_list x1 delta lim
263 go_up_char_fb c n x delta lim
266 go_up x | x ># lim = n
267 | otherwise = C# (chr# x) `c` go_up (x +# delta)
269 go_dn_char_fb c n x delta lim
272 go_dn x | x <# lim = n
273 | otherwise = C# (chr# x) `c` go_dn (x +# delta)
275 go_up_char_list x delta lim
278 go_up x | x ># lim = []
279 | otherwise = C# (chr# x) : go_up (x +# delta)
281 go_dn_char_list x delta lim
284 go_dn x | x <# lim = []
285 | otherwise = C# (chr# x) : go_dn (x +# delta)
289 %*********************************************************
291 \subsection{Type @Int@}
293 %*********************************************************
295 Be careful about these instances.
296 (a) remember that you have to count down as well as up e.g. [13,12..0]
297 (b) be careful of Int overflow
298 (c) remember that Int is bounded, so [1..] terminates at maxInt
300 Also NB that the Num class isn't available in this module.
303 instance Bounded Int where
307 instance Enum Int where
309 | x == maxBound = error "Prelude.Enum.succ{Int}: tried to take `succ' of maxBound"
310 | otherwise = x `plusInt` oneInt
312 | x == minBound = error "Prelude.Enum.pred{Int}: tried to take `pred' of minBound"
313 | otherwise = x `minusInt` oneInt
318 {-# INLINE enumFrom #-}
319 enumFrom (I# x) = eftInt x maxInt#
320 where I# maxInt# = maxInt
321 -- Blarg: technically I guess enumFrom isn't strict!
323 {-# INLINE enumFromTo #-}
324 enumFromTo (I# x) (I# y) = eftInt x y
326 {-# INLINE enumFromThen #-}
327 enumFromThen (I# x1) (I# x2) = efdInt x1 x2
329 {-# INLINE enumFromThenTo #-}
330 enumFromThenTo (I# x1) (I# x2) (I# y) = efdtInt x1 x2 y
332 {-# NOINLINE [1] eftInt #-}
333 {-# NOINLINE [1] efdInt #-}
334 {-# NOINLINE [1] efdtInt #-}
337 efdtInt = efdtIntList
340 "eftInt" forall x y. eftInt x y = build (\ c n -> eftIntFB c n x y)
341 "efdInt" forall x1 x2. efdInt x1 x2 = build (\ c n -> efdIntFB c n x1 x2)
342 "efdtInt" forall x1 x2 l. efdtInt x1 x2 l = build (\ c n -> efdtIntFB c n x1 x2 l)
344 "eftIntList" eftIntFB (:) [] = eftIntList
345 "efdIntList" efdIntFB (:) [] = efdIntList
346 "efdtIntList" efdtIntFB (:) [] = efdtIntList
350 {-# INLINE [0] eftIntFB #-}
351 eftIntFB c n x y | x ># y = n
354 go x = I# x `c` if x ==# y then n else go (x +# 1#)
355 -- Watch out for y=maxBound; hence ==, not >
356 -- Be very careful not to have more than one "c"
357 -- so that when eftInfFB is inlined we can inline
358 -- whatver is bound to "c"
360 eftIntList x y | x ># y = []
363 go x = I# x : if x ==# y then [] else go (x +# 1#)
366 -- For enumFromThenTo we give up on inlining; so we don't worry
367 -- about duplicating occurrences of "c"
368 {-# NOINLINE [0] efdtIntFB #-}
369 efdtIntFB c n x1 x2 y
370 | delta >=# 0# = if x1 ># y then n else go_up_int_fb c n x1 delta lim
371 | otherwise = if x1 <# y then n else go_dn_int_fb c n x1 delta lim
377 | delta >=# 0# = if x1 ># y then [] else go_up_int_list x1 delta lim
378 | otherwise = if x1 <# y then [] else go_dn_int_list x1 delta lim
383 {-# NOINLINE [0] efdIntFB #-}
385 | delta >=# 0# = case maxInt of I# y -> go_up_int_fb c n x1 delta (y -# delta)
386 | otherwise = case minInt of I# y -> go_dn_int_fb c n x1 delta (y -# delta)
391 | delta >=# 0# = case maxInt of I# y -> go_up_int_list x1 delta (y -# delta)
392 | otherwise = case minInt of I# y -> go_dn_int_list x1 delta (y -# delta)
396 -- In all of these, the (x +# delta) is guaranteed not to overflow
398 go_up_int_fb c n x delta lim
401 go_up x | x ># lim = I# x `c` n
402 | otherwise = I# x `c` go_up (x +# delta)
404 go_dn_int_fb c n x delta lim
407 go_dn x | x <# lim = I# x `c` n
408 | otherwise = I# x `c` go_dn (x +# delta)
410 go_up_int_list x delta lim
413 go_up x | x ># lim = [I# x]
414 | otherwise = I# x : go_up (x +# delta)
416 go_dn_int_list x delta lim
419 go_dn x | x <# lim = [I# x]
420 | otherwise = I# x : go_dn (x +# delta)