[project @ 2000-04-10 16:02:58 by simonpj]
[ghc-hetmet.git] / ghc / lib / std / PrelEnum.lhs
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
3 %
4 \section[PrelBounded]{Module @PrelBounded@}
5
6 Instances of Bounded for various datatypes.
7
8 \begin{code}
9 {-# OPTIONS -fcompiling-prelude -fno-implicit-prelude #-}
10
11 module PrelEnum(
12         Bounded(..), Enum(..),
13         enumFromBounded, enumFromThenBounded,
14
15         -- Instances for Bounded and Eum: (), Char, Int
16
17    ) where
18
19 import {-# SOURCE #-} PrelErr ( error )
20 import PrelBase
21 import PrelTup  ()      -- To make sure we look for the .hi file
22
23 default ()              -- Double isn't available yet
24 \end{code}
25
26
27 %*********************************************************
28 %*                                                      *
29 \subsection{Class declarations}
30 %*                                                      *
31 %*********************************************************
32
33 \begin{code}
34 class  Bounded a  where
35     minBound, maxBound :: a
36
37 class  Enum a   where
38     succ, pred          :: a -> a
39     toEnum              :: Int -> a
40     fromEnum            :: a -> Int
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]
45
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]
52
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)]
56
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)]
61   where
62     i_n1 = fromEnum n1
63     i_n2 = fromEnum n2
64 \end{code}
65
66
67 %*********************************************************
68 %*                                                      *
69 \subsection{Tuples}
70 %*                                                      *
71 %*********************************************************
72
73 \begin{code}
74 instance Bounded () where
75     minBound = ()
76     maxBound = ()
77
78 instance Enum () where
79     succ _      = error "Prelude.Enum.().succ: bad argment"
80     pred _      = error "Prelude.Enum.().pred: bad argument"
81
82     toEnum x | x == zeroInt = ()
83              | otherwise    = error "Prelude.Enum.().toEnum: bad argument"
84
85     fromEnum () = zeroInt
86     enumFrom ()         = [()]
87     enumFromThen () ()  = [()]
88     enumFromTo () ()    = [()]
89     enumFromThenTo () () () = [()]
90 \end{code}
91
92 \begin{code}
93 instance (Bounded a, Bounded b) => Bounded (a,b) where
94    minBound = (minBound, minBound)
95    maxBound = (maxBound, maxBound)
96
97 instance (Bounded a, Bounded b, Bounded c) => Bounded (a,b,c) where
98    minBound = (minBound, minBound, minBound)
99    maxBound = (maxBound, maxBound, maxBound)
100
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)
104 \end{code}
105
106
107 %*********************************************************
108 %*                                                      *
109 \subsection{Type @Bool@}
110 %*                                                      *
111 %*********************************************************
112
113 \begin{code}
114 instance Bounded Bool where
115   minBound = False
116   maxBound = True
117
118 instance Enum Bool where
119   succ False = True
120   succ True  = error "Prelude.Enum.Bool.succ: bad argment"
121
122   pred True  = False
123   pred False  = error "Prelude.Enum.Bool.pred: bad argment"
124
125   toEnum n | n == zeroInt = False
126            | n == oneInt  = True
127            | otherwise    = error "Prelude.Enum.Bool.toEnum: bad argment"
128
129   fromEnum False = zeroInt
130   fromEnum True  = oneInt
131
132   -- Use defaults for the rest
133   enumFrom     = enumFromBounded
134   enumFromThen = enumFromThenBounded
135 \end{code}
136
137 %*********************************************************
138 %*                                                      *
139 \subsection{Type @Ordering@}
140 %*                                                      *
141 %*********************************************************
142
143 \begin{code}
144 instance Bounded Ordering where
145   minBound = LT
146   maxBound = GT
147
148 instance Enum Ordering where
149   succ LT = EQ
150   succ EQ = GT
151   succ GT = error "Prelude.Enum.Ordering.succ: bad argment"
152
153   pred GT = EQ
154   pred EQ = LT
155   pred LT = error "Prelude.Enum.Ordering.pred: bad argment"
156
157   toEnum n | n == zeroInt = LT
158            | n == oneInt  = EQ
159            | n == twoInt  = GT
160   toEnum _ = error "Prelude.Enum.Ordering.toEnum: bad argment"
161
162   fromEnum LT = zeroInt
163   fromEnum EQ = oneInt
164   fromEnum GT = twoInt
165
166   -- Use defaults for the rest
167   enumFrom     = enumFromBounded
168   enumFromThen = enumFromThenBounded
169 \end{code}
170
171 %*********************************************************
172 %*                                                      *
173 \subsection{Type @Char@}
174 %*                                                      *
175 %*********************************************************
176
177 \begin{code}
178 instance  Bounded Char  where
179     minBound =  '\0'
180     maxBound =  '\255'
181
182 instance  Enum Char  where
183     succ (C# c#)
184        | not (ord# c# ==# 255#) = C# (chr# (ord# c# +# 1#))
185        | otherwise              = error ("Prelude.Enum.Char.succ: bad argument")
186     pred (C# c#)
187        | not (ord# c# ==# 0#)   = C# (chr# (ord# c# -# 1#))
188        | otherwise              = error ("Prelude.Enum.Char.pred: bad argument")
189
190     toEnum   = chr
191     fromEnum = ord
192
193     {-# INLINE enumFrom #-}
194     enumFrom (C# x) = eftChar (ord# x) 255#
195         -- Blarg: technically I guess enumFrom isn't strict!
196
197     {-# INLINE enumFromTo #-}
198     enumFromTo (C# x) (C# y) = eftChar (ord# x) (ord# y)
199     
200     {-# INLINE enumFromThen #-}
201     enumFromThen (C# x1) (C# x2) = efdChar (ord# x1) (ord# x2)
202     
203     {-# INLINE enumFromThenTo #-}
204     enumFromThenTo (C# x1) (C# x2) (C# y) = efdtChar (ord# x1) (ord# x2) (ord# y)
205
206 eftChar  = eftCharList
207 efdChar  = efdCharList
208 efdtChar = efdtCharList
209
210
211 {-# RULES
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
218  #-}
219
220
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
225                  where
226                     go x | x ># y    = n
227                          | otherwise = C# (chr# x) `c` go (x +# 1#)
228
229 eftCharList x y | x ># y    = [] 
230                 | otherwise = C# (chr# x) : eftCharList (x +# 1#) y
231
232
233 -- For enumFromThenTo we give up on inlining
234 efdCharFB c n x1 x2
235   | delta >=# 0# = go_up_char_fb c n x1 delta 255#
236   | otherwise    = go_dn_char_fb c n x1 delta 0#
237   where
238     delta = x2 -# x1
239
240 efdCharList x1 x2
241   | delta >=# 0# = go_up_char_list x1 delta 255#
242   | otherwise    = go_dn_char_list x1 delta 0#
243   where
244     delta = x2 -# x1
245
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
249   where
250     delta = x2 -# x1
251
252 efdtCharList x1 x2 lim
253   | delta >=# 0# = go_up_char_list x1 delta lim
254   | otherwise    = go_dn_char_list x1 delta lim
255   where
256     delta = x2 -# x1
257
258 go_up_char_fb c n x delta lim
259   = go_up x
260   where
261     go_up x | x ># lim  = n
262             | otherwise = C# (chr# x) `c` go_up (x +# delta)
263
264 go_dn_char_fb c n x delta lim
265   = go_dn x
266   where
267     go_dn x | x <# lim  = n
268             | otherwise = C# (chr# x) `c` go_dn (x +# delta)
269
270 go_up_char_list x delta lim
271   = go_up x
272   where
273     go_up x | x ># lim  = []
274             | otherwise = C# (chr# x) : go_up (x +# delta)
275
276 go_dn_char_list x delta lim
277   = go_dn x
278   where
279     go_dn x | x <# lim  = []
280             | otherwise = C# (chr# x) : go_dn (x +# delta)
281 \end{code}
282
283
284 %*********************************************************
285 %*                                                      *
286 \subsection{Type @Int@}
287 %*                                                      *
288 %*********************************************************
289
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
294
295 Also NB that the Num class isn't available in this module.
296         
297 \begin{code}
298 instance  Bounded Int where
299     minBound =  minInt
300     maxBound =  maxInt
301
302 instance  Enum Int  where
303     succ x  
304        | x == maxBound  = error "Prelude.Enum.succ{Int}: tried to take `succ' of maxBound"
305        | otherwise      = x `plusInt` oneInt
306     pred x
307        | x == minBound  = error "Prelude.Enum.pred{Int}: tried to take `pred' of minBound"
308        | otherwise      = x `minusInt` oneInt
309
310     toEnum   x = x
311     fromEnum x = x
312
313     {-# INLINE enumFrom #-}
314     enumFrom (I# x) = eftInt x 2147483647#
315         -- Blarg: technically I guess enumFrom isn't strict!
316
317     {-# INLINE enumFromTo #-}
318     enumFromTo (I# x) (I# y) = eftInt x y
319
320     {-# INLINE enumFromThen #-}
321     enumFromThen (I# x1) (I# x2) = efdInt x1 x2
322
323     {-# INLINE enumFromThenTo #-}
324     enumFromThenTo (I# x1) (I# x2) (I# y) = efdtInt x1 x2 y
325
326 eftInt  = eftIntList
327 efdInt  = efdIntList
328 efdtInt = efdtIntList
329
330 {-# RULES
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)
334
335 "eftIntList"    eftIntFB  (:) [] = eftIntList
336 "efdIntList"    efdIntFB  (:) [] = efdIntList
337 "efdtIntList"   efdtIntFB (:) [] = efdtIntList
338  #-}
339
340
341 {-# INLINE eftIntFB #-}
342 eftIntFB c n x y | x ># y    = n        
343                  | otherwise = go x
344                  where
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"
350
351 eftIntList x y | x ># y    = []
352                | otherwise = go x
353                where
354                  go x = I# x : if x ==# y then [] else go (x +# 1#)
355
356
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 
362   where
363     delta = x2 -# x1
364     lim   = y -# delta
365
366 efdtIntList x1 x2 y
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
369   where
370     delta = x2 -# x1
371     lim   = y -# delta
372
373 efdIntFB c n x1 x2
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)
376   where
377     delta = x2 -# x1
378
379 efdIntList x1 x2
380   | delta >=# 0# = go_up_int_list x1 delta (  2147483647#  -# delta)
381   | otherwise    = go_dn_int_list x1 delta ((-2147483648#) -# delta)
382   where
383     delta = x2 -# x1
384
385 -- In all of these, the (x +# delta) is guaranteed not to overflow
386
387 go_up_int_fb c n x delta lim
388   = go_up x
389   where
390     go_up x | x ># lim  = I# x `c` n
391             | otherwise = I# x `c` go_up (x +# delta)
392
393 go_dn_int_fb c n x delta lim 
394   = go_dn x
395   where
396     go_dn x | x <# lim  = I# x `c` n
397             | otherwise = I# x `c` go_dn (x +# delta)
398
399 go_up_int_list x delta lim
400   = go_up x
401   where
402     go_up x | x ># lim  = [I# x]
403             | otherwise = I# x : go_up (x +# delta)
404
405 go_dn_int_list x delta lim 
406   = go_dn x
407   where
408     go_dn x | x <# lim  = [I# x]
409             | otherwise = I# x : go_dn (x +# delta)
410 \end{code}
411