1 % -----------------------------------------------------------------------------
2 % $Id: Enum.lhs,v 1.6 2001/12/21 15:07:22 simonmar Exp $
4 % (c) The University of Glasgow, 1992-2000
7 \section[GHC.Bounded]{Module @GHC.Bounded@}
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 #-} GHC.Err ( error )
24 import Data.Tuple () -- for dependencies
25 default () -- Double isn't available yet
29 %*********************************************************
31 \subsection{Class declarations}
33 %*********************************************************
37 minBound, maxBound :: a
43 enumFrom :: a -> [a] -- [n..]
44 enumFromThen :: a -> a -> [a] -- [n,n'..]
45 enumFromTo :: a -> a -> [a] -- [n..m]
46 enumFromThenTo :: a -> a -> a -> [a] -- [n,n'..m]
48 succ = toEnum . (`plusInt` oneInt) . fromEnum
49 pred = toEnum . (`minusInt` oneInt) . fromEnum
50 enumFrom x = map toEnum [fromEnum x ..]
51 enumFromThen x y = map toEnum [fromEnum x, fromEnum y ..]
52 enumFromTo x y = map toEnum [fromEnum x .. fromEnum y]
53 enumFromThenTo x1 x2 y = map toEnum [fromEnum x1, fromEnum x2 .. fromEnum y]
55 -- Default methods for bounded enumerations
56 boundedEnumFrom :: (Enum a, Bounded a) => a -> [a]
57 boundedEnumFrom n = map toEnum [fromEnum n .. fromEnum (maxBound `asTypeOf` n)]
59 boundedEnumFromThen :: (Enum a, Bounded a) => a -> a -> [a]
60 boundedEnumFromThen n1 n2
61 | i_n2 >= i_n1 = map toEnum [i_n1, i_n2 .. fromEnum (maxBound `asTypeOf` n1)]
62 | otherwise = map toEnum [i_n1, i_n2 .. fromEnum (minBound `asTypeOf` n1)]
69 %*********************************************************
73 %*********************************************************
76 instance Bounded () where
80 instance Enum () where
81 succ _ = error "Prelude.Enum.().succ: bad argment"
82 pred _ = error "Prelude.Enum.().pred: bad argument"
84 toEnum x | x == zeroInt = ()
85 | otherwise = error "Prelude.Enum.().toEnum: bad argument"
89 enumFromThen () () = [()]
90 enumFromTo () () = [()]
91 enumFromThenTo () () () = [()]
95 instance (Bounded a, Bounded b) => Bounded (a,b) where
96 minBound = (minBound, minBound)
97 maxBound = (maxBound, maxBound)
99 instance (Bounded a, Bounded b, Bounded c) => Bounded (a,b,c) where
100 minBound = (minBound, minBound, minBound)
101 maxBound = (maxBound, maxBound, maxBound)
103 instance (Bounded a, Bounded b, Bounded c, Bounded d) => Bounded (a,b,c,d) where
104 minBound = (minBound, minBound, minBound, minBound)
105 maxBound = (maxBound, maxBound, maxBound, maxBound)
109 %*********************************************************
111 \subsection{Type @Bool@}
113 %*********************************************************
116 instance Bounded Bool where
120 instance Enum Bool where
122 succ True = error "Prelude.Enum.Bool.succ: bad argment"
125 pred False = error "Prelude.Enum.Bool.pred: bad argment"
127 toEnum n | n == zeroInt = False
129 | otherwise = error "Prelude.Enum.Bool.toEnum: bad argment"
131 fromEnum False = zeroInt
132 fromEnum True = oneInt
134 -- Use defaults for the rest
135 enumFrom = boundedEnumFrom
136 enumFromThen = boundedEnumFromThen
139 %*********************************************************
141 \subsection{Type @Ordering@}
143 %*********************************************************
146 instance Bounded Ordering where
150 instance Enum Ordering where
153 succ GT = error "Prelude.Enum.Ordering.succ: bad argment"
157 pred LT = error "Prelude.Enum.Ordering.pred: bad argment"
159 toEnum n | n == zeroInt = LT
162 toEnum _ = error "Prelude.Enum.Ordering.toEnum: bad argment"
164 fromEnum LT = zeroInt
168 -- Use defaults for the rest
169 enumFrom = boundedEnumFrom
170 enumFromThen = boundedEnumFromThen
173 %*********************************************************
175 \subsection{Type @Char@}
177 %*********************************************************
180 instance Bounded Char where
182 maxBound = '\x10FFFF'
184 instance Enum Char where
186 | not (ord# c# ==# 0x10FFFF#) = C# (chr# (ord# c# +# 1#))
187 | otherwise = error ("Prelude.Enum.Char.succ: bad argument")
189 | not (ord# c# ==# 0#) = C# (chr# (ord# c# -# 1#))
190 | otherwise = error ("Prelude.Enum.Char.pred: bad argument")
195 {-# INLINE enumFrom #-}
196 enumFrom (C# x) = eftChar (ord# x) 0x10FFFF#
197 -- Blarg: technically I guess enumFrom isn't strict!
199 {-# INLINE enumFromTo #-}
200 enumFromTo (C# x) (C# y) = eftChar (ord# x) (ord# y)
202 {-# INLINE enumFromThen #-}
203 enumFromThen (C# x1) (C# x2) = efdChar (ord# x1) (ord# x2)
205 {-# INLINE enumFromThenTo #-}
206 enumFromThenTo (C# x1) (C# x2) (C# y) = efdtChar (ord# x1) (ord# x2) (ord# y)
208 {-# NOINLINE [1] eftChar #-}
209 {-# NOINLINE [1] efdChar #-}
210 {-# NOINLINE [1] efdtChar #-}
211 eftChar = eftCharList
212 efdChar = efdCharList
213 efdtChar = efdtCharList
216 "eftChar" forall x y. eftChar x y = build (\c n -> eftCharFB c n x y)
217 "efdChar" forall x1 x2. efdChar x1 x2 = build (\ c n -> efdCharFB c n x1 x2)
218 "efdtChar" forall x1 x2 l. efdtChar x1 x2 l = build (\ c n -> efdtCharFB c n x1 x2 l)
219 "eftCharList" eftCharFB (:) [] = eftCharList
220 "efdCharList" efdCharFB (:) [] = efdCharList
221 "efdtCharList" efdtCharFB (:) [] = efdtCharList
225 -- We can do better than for Ints because we don't
226 -- have hassles about arithmetic overflow at maxBound
227 {-# INLINE [0] eftCharFB #-}
228 eftCharFB c n x y = go x
231 | otherwise = C# (chr# x) `c` go (x +# 1#)
233 eftCharList x y | x ># y = []
234 | otherwise = C# (chr# x) : eftCharList (x +# 1#) y
237 -- For enumFromThenTo we give up on inlining
238 {-# NOINLINE [0] efdCharFB #-}
240 | delta >=# 0# = go_up_char_fb c n x1 delta 0x10FFFF#
241 | otherwise = go_dn_char_fb c n x1 delta 0#
246 | delta >=# 0# = go_up_char_list x1 delta 0x10FFFF#
247 | otherwise = go_dn_char_list x1 delta 0#
251 {-# NOINLINE [0] efdtCharFB #-}
252 efdtCharFB c n x1 x2 lim
253 | delta >=# 0# = go_up_char_fb c n x1 delta lim
254 | otherwise = go_dn_char_fb c n x1 delta lim
258 efdtCharList x1 x2 lim
259 | delta >=# 0# = go_up_char_list x1 delta lim
260 | otherwise = go_dn_char_list x1 delta lim
264 go_up_char_fb c n x delta lim
267 go_up x | x ># lim = n
268 | otherwise = C# (chr# x) `c` go_up (x +# delta)
270 go_dn_char_fb c n x delta lim
273 go_dn x | x <# lim = n
274 | otherwise = C# (chr# x) `c` go_dn (x +# delta)
276 go_up_char_list x delta lim
279 go_up x | x ># lim = []
280 | otherwise = C# (chr# x) : go_up (x +# delta)
282 go_dn_char_list x delta lim
285 go_dn x | x <# lim = []
286 | otherwise = C# (chr# x) : go_dn (x +# delta)
290 %*********************************************************
292 \subsection{Type @Int@}
294 %*********************************************************
296 Be careful about these instances.
297 (a) remember that you have to count down as well as up e.g. [13,12..0]
298 (b) be careful of Int overflow
299 (c) remember that Int is bounded, so [1..] terminates at maxInt
301 Also NB that the Num class isn't available in this module.
304 instance Bounded Int where
308 instance Enum Int where
310 | x == maxBound = error "Prelude.Enum.succ{Int}: tried to take `succ' of maxBound"
311 | otherwise = x `plusInt` oneInt
313 | x == minBound = error "Prelude.Enum.pred{Int}: tried to take `pred' of minBound"
314 | otherwise = x `minusInt` oneInt
319 {-# INLINE enumFrom #-}
320 enumFrom (I# x) = eftInt x maxInt#
321 where I# maxInt# = maxInt
322 -- Blarg: technically I guess enumFrom isn't strict!
324 {-# INLINE enumFromTo #-}
325 enumFromTo (I# x) (I# y) = eftInt x y
327 {-# INLINE enumFromThen #-}
328 enumFromThen (I# x1) (I# x2) = efdInt x1 x2
330 {-# INLINE enumFromThenTo #-}
331 enumFromThenTo (I# x1) (I# x2) (I# y) = efdtInt x1 x2 y
333 {-# NOINLINE [1] eftInt #-}
334 {-# NOINLINE [1] efdInt #-}
335 {-# NOINLINE [1] efdtInt #-}
338 efdtInt = efdtIntList
341 "eftInt" forall x y. eftInt x y = build (\ c n -> eftIntFB c n x y)
342 "efdInt" forall x1 x2. efdInt x1 x2 = build (\ c n -> efdIntFB c n x1 x2)
343 "efdtInt" forall x1 x2 l. efdtInt x1 x2 l = build (\ c n -> efdtIntFB c n x1 x2 l)
345 "eftIntList" eftIntFB (:) [] = eftIntList
346 "efdIntList" efdIntFB (:) [] = efdIntList
347 "efdtIntList" efdtIntFB (:) [] = efdtIntList
351 {-# INLINE [0] eftIntFB #-}
352 eftIntFB c n x y | x ># y = n
355 go x = I# x `c` if x ==# y then n else go (x +# 1#)
356 -- Watch out for y=maxBound; hence ==, not >
357 -- Be very careful not to have more than one "c"
358 -- so that when eftInfFB is inlined we can inline
359 -- whatver is bound to "c"
361 eftIntList x y | x ># y = []
364 go x = I# x : if x ==# y then [] else go (x +# 1#)
367 -- For enumFromThenTo we give up on inlining; so we don't worry
368 -- about duplicating occurrences of "c"
369 {-# NOINLINE [0] efdtIntFB #-}
370 efdtIntFB c n x1 x2 y
371 | delta >=# 0# = if x1 ># y then n else go_up_int_fb c n x1 delta lim
372 | otherwise = if x1 <# y then n else go_dn_int_fb c n x1 delta lim
378 | delta >=# 0# = if x1 ># y then [] else go_up_int_list x1 delta lim
379 | otherwise = if x1 <# y then [] else go_dn_int_list x1 delta lim
384 {-# NOINLINE [0] efdIntFB #-}
386 | delta >=# 0# = case maxInt of I# y -> go_up_int_fb c n x1 delta (y -# delta)
387 | otherwise = case minInt of I# y -> go_dn_int_fb c n x1 delta (y -# delta)
392 | delta >=# 0# = case maxInt of I# y -> go_up_int_list x1 delta (y -# delta)
393 | otherwise = case minInt of I# y -> go_dn_int_list x1 delta (y -# delta)
397 -- In all of these, the (x +# delta) is guaranteed not to overflow
399 go_up_int_fb c n x delta lim
402 go_up x | x ># lim = I# x `c` n
403 | otherwise = I# x `c` go_up (x +# delta)
405 go_dn_int_fb c n x delta lim
408 go_dn x | x <# lim = I# x `c` n
409 | otherwise = I# x `c` go_dn (x +# delta)
411 go_up_int_list x delta lim
414 go_up x | x ># lim = [I# x]
415 | otherwise = I# x : go_up (x +# delta)
417 go_dn_int_list x delta lim
420 go_dn x | x <# lim = [I# x]
421 | otherwise = I# x : go_dn (x +# delta)