[project @ 2001-12-21 15:07:20 by simonmar]
[packages/old-time.git] / GHC / Enum.lhs
1 % -----------------------------------------------------------------------------
2 % $Id: Enum.lhs,v 1.6 2001/12/21 15:07:22 simonmar Exp $
3 %
4 % (c) The University of Glasgow, 1992-2000
5 %
6
7 \section[GHC.Bounded]{Module @GHC.Bounded@}
8
9 Instances of Bounded for various datatypes.
10
11 \begin{code}
12 {-# OPTIONS -fno-implicit-prelude #-}
13
14 module GHC.Enum(
15         Bounded(..), Enum(..),
16         boundedEnumFrom, boundedEnumFromThen,
17
18         -- Instances for Bounded and Eum: (), Char, Int
19
20    ) where
21
22 import {-# SOURCE #-} GHC.Err ( error )
23 import GHC.Base
24 import Data.Tuple       ()              -- for dependencies
25 default ()              -- Double isn't available yet
26 \end{code}
27
28
29 %*********************************************************
30 %*                                                      *
31 \subsection{Class declarations}
32 %*                                                      *
33 %*********************************************************
34
35 \begin{code}
36 class  Bounded a  where
37     minBound, maxBound :: a
38
39 class  Enum a   where
40     succ, pred          :: a -> a
41     toEnum              :: Int -> a
42     fromEnum            :: a -> Int
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]
47
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]
54
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)]
58
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)]
63   where
64     i_n1 = fromEnum n1
65     i_n2 = fromEnum n2
66 \end{code}
67
68
69 %*********************************************************
70 %*                                                      *
71 \subsection{Tuples}
72 %*                                                      *
73 %*********************************************************
74
75 \begin{code}
76 instance Bounded () where
77     minBound = ()
78     maxBound = ()
79
80 instance Enum () where
81     succ _      = error "Prelude.Enum.().succ: bad argment"
82     pred _      = error "Prelude.Enum.().pred: bad argument"
83
84     toEnum x | x == zeroInt = ()
85              | otherwise    = error "Prelude.Enum.().toEnum: bad argument"
86
87     fromEnum () = zeroInt
88     enumFrom ()         = [()]
89     enumFromThen () ()  = [()]
90     enumFromTo () ()    = [()]
91     enumFromThenTo () () () = [()]
92 \end{code}
93
94 \begin{code}
95 instance (Bounded a, Bounded b) => Bounded (a,b) where
96    minBound = (minBound, minBound)
97    maxBound = (maxBound, maxBound)
98
99 instance (Bounded a, Bounded b, Bounded c) => Bounded (a,b,c) where
100    minBound = (minBound, minBound, minBound)
101    maxBound = (maxBound, maxBound, maxBound)
102
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)
106 \end{code}
107
108
109 %*********************************************************
110 %*                                                      *
111 \subsection{Type @Bool@}
112 %*                                                      *
113 %*********************************************************
114
115 \begin{code}
116 instance Bounded Bool where
117   minBound = False
118   maxBound = True
119
120 instance Enum Bool where
121   succ False = True
122   succ True  = error "Prelude.Enum.Bool.succ: bad argment"
123
124   pred True  = False
125   pred False  = error "Prelude.Enum.Bool.pred: bad argment"
126
127   toEnum n | n == zeroInt = False
128            | n == oneInt  = True
129            | otherwise    = error "Prelude.Enum.Bool.toEnum: bad argment"
130
131   fromEnum False = zeroInt
132   fromEnum True  = oneInt
133
134   -- Use defaults for the rest
135   enumFrom     = boundedEnumFrom
136   enumFromThen = boundedEnumFromThen
137 \end{code}
138
139 %*********************************************************
140 %*                                                      *
141 \subsection{Type @Ordering@}
142 %*                                                      *
143 %*********************************************************
144
145 \begin{code}
146 instance Bounded Ordering where
147   minBound = LT
148   maxBound = GT
149
150 instance Enum Ordering where
151   succ LT = EQ
152   succ EQ = GT
153   succ GT = error "Prelude.Enum.Ordering.succ: bad argment"
154
155   pred GT = EQ
156   pred EQ = LT
157   pred LT = error "Prelude.Enum.Ordering.pred: bad argment"
158
159   toEnum n | n == zeroInt = LT
160            | n == oneInt  = EQ
161            | n == twoInt  = GT
162   toEnum _ = error "Prelude.Enum.Ordering.toEnum: bad argment"
163
164   fromEnum LT = zeroInt
165   fromEnum EQ = oneInt
166   fromEnum GT = twoInt
167
168   -- Use defaults for the rest
169   enumFrom     = boundedEnumFrom
170   enumFromThen = boundedEnumFromThen
171 \end{code}
172
173 %*********************************************************
174 %*                                                      *
175 \subsection{Type @Char@}
176 %*                                                      *
177 %*********************************************************
178
179 \begin{code}
180 instance  Bounded Char  where
181     minBound =  '\0'
182     maxBound =  '\x10FFFF'
183
184 instance  Enum Char  where
185     succ (C# c#)
186        | not (ord# c# ==# 0x10FFFF#) = C# (chr# (ord# c# +# 1#))
187        | otherwise              = error ("Prelude.Enum.Char.succ: bad argument")
188     pred (C# c#)
189        | not (ord# c# ==# 0#)   = C# (chr# (ord# c# -# 1#))
190        | otherwise              = error ("Prelude.Enum.Char.pred: bad argument")
191
192     toEnum   = chr
193     fromEnum = ord
194
195     {-# INLINE enumFrom #-}
196     enumFrom (C# x) = eftChar (ord# x) 0x10FFFF#
197         -- Blarg: technically I guess enumFrom isn't strict!
198
199     {-# INLINE enumFromTo #-}
200     enumFromTo (C# x) (C# y) = eftChar (ord# x) (ord# y)
201     
202     {-# INLINE enumFromThen #-}
203     enumFromThen (C# x1) (C# x2) = efdChar (ord# x1) (ord# x2)
204     
205     {-# INLINE enumFromThenTo #-}
206     enumFromThenTo (C# x1) (C# x2) (C# y) = efdtChar (ord# x1) (ord# x2) (ord# y)
207
208 {-# NOINLINE [1] eftChar #-}
209 {-# NOINLINE [1] efdChar #-}
210 {-# NOINLINE [1] efdtChar #-}
211 eftChar  = eftCharList
212 efdChar  = efdCharList
213 efdtChar = efdtCharList
214
215 {-# RULES
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
222  #-}
223
224
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
229                  where
230                     go x | x ># y    = n
231                          | otherwise = C# (chr# x) `c` go (x +# 1#)
232
233 eftCharList x y | x ># y    = [] 
234                 | otherwise = C# (chr# x) : eftCharList (x +# 1#) y
235
236
237 -- For enumFromThenTo we give up on inlining
238 {-# NOINLINE [0] efdCharFB #-}
239 efdCharFB c n x1 x2
240   | delta >=# 0# = go_up_char_fb c n x1 delta 0x10FFFF#
241   | otherwise    = go_dn_char_fb c n x1 delta 0#
242   where
243     delta = x2 -# x1
244
245 efdCharList x1 x2
246   | delta >=# 0# = go_up_char_list x1 delta 0x10FFFF#
247   | otherwise    = go_dn_char_list x1 delta 0#
248   where
249     delta = x2 -# x1
250
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
255   where
256     delta = x2 -# x1
257
258 efdtCharList x1 x2 lim
259   | delta >=# 0# = go_up_char_list x1 delta lim
260   | otherwise    = go_dn_char_list x1 delta lim
261   where
262     delta = x2 -# x1
263
264 go_up_char_fb c n x delta lim
265   = go_up x
266   where
267     go_up x | x ># lim  = n
268             | otherwise = C# (chr# x) `c` go_up (x +# delta)
269
270 go_dn_char_fb c n x delta lim
271   = go_dn x
272   where
273     go_dn x | x <# lim  = n
274             | otherwise = C# (chr# x) `c` go_dn (x +# delta)
275
276 go_up_char_list x delta lim
277   = go_up x
278   where
279     go_up x | x ># lim  = []
280             | otherwise = C# (chr# x) : go_up (x +# delta)
281
282 go_dn_char_list x delta lim
283   = go_dn x
284   where
285     go_dn x | x <# lim  = []
286             | otherwise = C# (chr# x) : go_dn (x +# delta)
287 \end{code}
288
289
290 %*********************************************************
291 %*                                                      *
292 \subsection{Type @Int@}
293 %*                                                      *
294 %*********************************************************
295
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
300
301 Also NB that the Num class isn't available in this module.
302         
303 \begin{code}
304 instance  Bounded Int where
305     minBound =  minInt
306     maxBound =  maxInt
307
308 instance  Enum Int  where
309     succ x  
310        | x == maxBound  = error "Prelude.Enum.succ{Int}: tried to take `succ' of maxBound"
311        | otherwise      = x `plusInt` oneInt
312     pred x
313        | x == minBound  = error "Prelude.Enum.pred{Int}: tried to take `pred' of minBound"
314        | otherwise      = x `minusInt` oneInt
315
316     toEnum   x = x
317     fromEnum x = x
318
319     {-# INLINE enumFrom #-}
320     enumFrom (I# x) = eftInt x maxInt#
321         where I# maxInt# = maxInt
322         -- Blarg: technically I guess enumFrom isn't strict!
323
324     {-# INLINE enumFromTo #-}
325     enumFromTo (I# x) (I# y) = eftInt x y
326
327     {-# INLINE enumFromThen #-}
328     enumFromThen (I# x1) (I# x2) = efdInt x1 x2
329
330     {-# INLINE enumFromThenTo #-}
331     enumFromThenTo (I# x1) (I# x2) (I# y) = efdtInt x1 x2 y
332
333 {-# NOINLINE [1] eftInt #-}
334 {-# NOINLINE [1] efdInt #-}
335 {-# NOINLINE [1] efdtInt #-}
336 eftInt  = eftIntList
337 efdInt  = efdIntList
338 efdtInt = efdtIntList
339
340 {-# RULES
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)
344
345 "eftIntList"    eftIntFB  (:) [] = eftIntList
346 "efdIntList"    efdIntFB  (:) [] = efdIntList
347 "efdtIntList"   efdtIntFB (:) [] = efdtIntList
348  #-}
349
350
351 {-# INLINE [0] eftIntFB #-}
352 eftIntFB c n x y | x ># y    = n        
353                  | otherwise = go x
354                  where
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"
360
361 eftIntList x y | x ># y    = []
362                | otherwise = go x
363                where
364                  go x = I# x : if x ==# y then [] else go (x +# 1#)
365
366
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 
373   where
374     delta = x2 -# x1
375     lim   = y -# delta
376
377 efdtIntList x1 x2 y
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
380   where
381     delta = x2 -# x1
382     lim   = y -# delta
383
384 {-# NOINLINE [0] efdIntFB #-}
385 efdIntFB c n x1 x2
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)
388   where
389     delta = x2 -# x1
390
391 efdIntList x1 x2
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)
394   where
395     delta = x2 -# x1
396
397 -- In all of these, the (x +# delta) is guaranteed not to overflow
398
399 go_up_int_fb c n x delta lim
400   = go_up x
401   where
402     go_up x | x ># lim  = I# x `c` n
403             | otherwise = I# x `c` go_up (x +# delta)
404
405 go_dn_int_fb c n x delta lim 
406   = go_dn x
407   where
408     go_dn x | x <# lim  = I# x `c` n
409             | otherwise = I# x `c` go_dn (x +# delta)
410
411 go_up_int_list x delta lim
412   = go_up x
413   where
414     go_up x | x ># lim  = [I# x]
415             | otherwise = I# x : go_up (x +# delta)
416
417 go_dn_int_list x delta lim 
418   = go_dn x
419   where
420     go_dn x | x <# lim  = [I# x]
421             | otherwise = I# x : go_dn (x +# delta)
422 \end{code}
423