[project @ 1999-08-31 15:29:00 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 -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 \end{code}
23
24
25 %*********************************************************
26 %*                                                      *
27 \subsection{Class declarations}
28 %*                                                      *
29 %*********************************************************
30
31 \begin{code}
32 class  Bounded a  where
33     minBound, maxBound :: a
34
35 class  Enum a   where
36     succ, pred          :: a -> a
37     toEnum              :: Int -> a
38     fromEnum            :: a -> Int
39     enumFrom            :: a -> [a]             -- [n..]
40     enumFromThen        :: a -> a -> [a]        -- [n,n'..]
41     enumFromTo          :: a -> a -> [a]        -- [n..m]
42     enumFromThenTo      :: a -> a -> a -> [a]   -- [n,n'..m]
43
44     succ                   = toEnum . (`plusInt` oneInt)  . fromEnum
45     pred                   = toEnum . (`minusInt` oneInt) . fromEnum
46     enumFrom x             = map toEnum [fromEnum x ..]
47     enumFromThen x y       = map toEnum [fromEnum x, fromEnum y ..]
48     enumFromTo x y         = map toEnum [fromEnum x .. fromEnum y]
49     enumFromThenTo x1 x2 y = map toEnum [fromEnum x1, fromEnum x2 .. fromEnum y]
50
51 -- Default methods for bounded enumerations
52 enumFromBounded :: (Enum a, Bounded a) => a -> [a]
53 enumFromBounded n = map toEnum [fromEnum n .. fromEnum (maxBound `asTypeOf` n)]
54
55 enumFromThenBounded :: (Enum a, Bounded a) => a -> a -> [a]
56 enumFromThenBounded n1 n2 
57   | i_n2 >= i_n1  = map toEnum [i_n1, i_n2 .. fromEnum (maxBound `asTypeOf` n1)]
58   | otherwise     = map toEnum [i_n1, i_n2 .. fromEnum (minBound `asTypeOf` n1)]
59   where
60     i_n1 = fromEnum n1
61     i_n2 = fromEnum n2
62 \end{code}
63
64
65 %*********************************************************
66 %*                                                      *
67 \subsection{Tuples}
68 %*                                                      *
69 %*********************************************************
70
71 \begin{code}
72 instance Bounded () where
73     minBound = ()
74     maxBound = ()
75
76 instance Enum () where
77     succ _      = error "Prelude.Enum.().succ: bad argment"
78     pred _      = error "Prelude.Enum.().pred: bad argument"
79
80     toEnum x | x == zeroInt = ()
81              | otherwise    = error "Prelude.Enum.().toEnum: bad argument"
82
83     fromEnum () = zeroInt
84     enumFrom ()         = [()]
85     enumFromThen () ()  = [()]
86     enumFromTo () ()    = [()]
87     enumFromThenTo () () () = [()]
88 \end{code}
89
90 \begin{code}
91 instance (Bounded a, Bounded b) => Bounded (a,b) where
92    minBound = (minBound, minBound)
93    maxBound = (maxBound, maxBound)
94
95 instance (Bounded a, Bounded b, Bounded c) => Bounded (a,b,c) where
96    minBound = (minBound, minBound, minBound)
97    maxBound = (maxBound, maxBound, maxBound)
98
99 instance (Bounded a, Bounded b, Bounded c, Bounded d) => Bounded (a,b,c,d) where
100    minBound = (minBound, minBound, minBound, minBound)
101    maxBound = (maxBound, maxBound, maxBound, maxBound)
102 \end{code}
103
104
105 %*********************************************************
106 %*                                                      *
107 \subsection{Type @Bool@}
108 %*                                                      *
109 %*********************************************************
110
111 \begin{code}
112 instance Bounded Bool where
113   minBound = False
114   maxBound = True
115
116 instance Enum Bool where
117   succ False = True
118   succ True  = error "Prelude.Enum.Bool.succ: bad argment"
119
120   pred True  = False
121   pred False  = error "Prelude.Enum.Bool.pred: bad argment"
122
123   toEnum n | n == zeroInt = False
124            | n == oneInt  = True
125            | otherwise    = error "Prelude.Enum.Bool.toEnum: bad argment"
126
127   fromEnum False = zeroInt
128   fromEnum True  = oneInt
129
130   -- Use defaults for the rest
131   enumFrom     = enumFromBounded
132   enumFromThen = enumFromThenBounded
133 \end{code}
134
135 %*********************************************************
136 %*                                                      *
137 \subsection{Type @Ordering@}
138 %*                                                      *
139 %*********************************************************
140
141 \begin{code}
142 instance Bounded Ordering where
143   minBound = LT
144   maxBound = GT
145
146 instance Enum Ordering where
147   succ LT = EQ
148   succ EQ = GT
149   succ GT = error "Prelude.Enum.Ordering.succ: bad argment"
150
151   pred GT = EQ
152   pred EQ = LT
153   pred LT = error "Prelude.Enum.Ordering.pred: bad argment"
154
155   toEnum n | n == zeroInt = LT
156            | n == oneInt  = EQ
157            | n == twoInt  = GT
158   toEnum _ = error "Prelude.Enum.Ordering.toEnum: bad argment"
159
160   fromEnum LT = zeroInt
161   fromEnum EQ = oneInt
162   fromEnum GT = twoInt
163
164   -- Use defaults for the rest
165   enumFrom     = enumFromBounded
166   enumFromThen = enumFromThenBounded
167 \end{code}
168
169 %*********************************************************
170 %*                                                      *
171 \subsection{Type @Char@}
172 %*                                                      *
173 %*********************************************************
174
175 \begin{code}
176 instance  Bounded Char  where
177     minBound =  '\0'
178     maxBound =  '\255'
179
180 instance  Enum Char  where
181     succ (C# c#)
182        | not (ord# c# ==# 255#) = C# (chr# (ord# c# +# 1#))
183        | otherwise              = error ("Prelude.Enum.Char.succ: bad argument")
184     pred (C# c#)
185        | not (ord# c# ==# 0#)   = C# (chr# (ord# c# -# 1#))
186        | otherwise              = error ("Prelude.Enum.Char.pred: bad argument")
187
188     toEnum   = chr
189     fromEnum = ord
190
191     {-# INLINE enumFrom #-}
192     enumFrom (C# x) = build (\ c n -> eftCharFB c n (ord# x) 255#)
193         -- Blarg: technically I guess enumFrom isn't strict!
194
195     {-# INLINE enumFromTo #-}
196     enumFromTo (C# x) (C# y) = build (\ c n -> eftCharFB c n (ord# x) (ord# y))
197
198     {-# INLINE enumFromThen #-}
199     enumFromThen (C# x1) (C# x2) = build (\ c n -> efdCharFB c n (ord# x1) (ord# x2))
200
201     {-# INLINE enumFromThenTo #-}
202     enumFromThenTo (C# x1) (C# x2) (C# y) = build (\ c n -> efdtCharFB c n (ord# x1) (ord# x2) (ord# y))
203
204 -- We can do better than for Ints because we don't
205 -- have hassles about arithmetic overflow at maxBound
206 {-# INLINE eftCharFB #-}
207 eftCharFB c n x y = go x
208                  where
209                     go x | x ># y    = n
210                          | otherwise = C# (chr# x) `c` go (x +# 1#)
211
212 eftCharList x y | x ># y    = [] 
213                 | otherwise = C# (chr# x) : eftCharList (x +# 1#) y
214
215
216 -- For enumFromThenTo we give up on inlining
217 efdCharFB c n x1 x2
218   | delta >=# 0# = go_up_char_fb c n x1 delta 255#
219   | otherwise    = go_dn_char_fb c n x1 delta 0#
220   where
221     delta = x2 -# x1
222
223 efdCharList x1 x2
224   | delta >=# 0# = go_up_char_list x1 delta 255#
225   | otherwise    = go_dn_char_list x1 delta 0#
226   where
227     delta = x2 -# x1
228
229 efdtCharFB c n x1 x2 lim
230   | delta >=# 0# = go_up_char_fb c n x1 delta lim
231   | otherwise    = go_dn_char_fb c n x1 delta lim
232   where
233     delta = x2 -# x1
234
235 efdtCharList x1 x2 lim
236   | delta >=# 0# = go_up_char_list x1 delta lim
237   | otherwise    = go_dn_char_list x1 delta lim
238   where
239     delta = x2 -# x1
240
241 go_up_char_fb c n x delta lim
242   = go_up x
243   where
244     go_up x | x ># lim  = n
245             | otherwise = C# (chr# x) `c` go_up (x +# delta)
246
247 go_dn_char_fb c n x delta lim
248   = go_dn x
249   where
250     go_dn x | x <# lim  = n
251             | otherwise = C# (chr# x) `c` go_dn (x +# delta)
252
253 go_up_char_list x delta lim
254   = go_up x
255   where
256     go_up x | x ># lim  = []
257             | otherwise = C# (chr# x) : go_up (x +# delta)
258
259 go_dn_char_list x delta lim
260   = go_dn x
261   where
262     go_dn x | x <# lim  = []
263             | otherwise = C# (chr# x) : go_dn (x +# delta)
264
265
266 {-# RULES
267 "eftCharList"   eftCharFB  (:) [] = eftCharList
268 "efdCharList"   efdCharFB  (:) [] = efdCharList
269 "efdtCharList"  efdtCharFB (:) [] = efdtCharList
270  #-}
271 \end{code}
272
273
274 %*********************************************************
275 %*                                                      *
276 \subsection{Type @Int@}
277 %*                                                      *
278 %*********************************************************
279
280 Be careful about these instances.  
281         (a) remember that you have to count down as well as up e.g. [13,12..0]
282         (b) be careful of Int overflow
283         (c) remember that Int is bounded, so [1..] terminates at maxInt
284
285 Also NB that the Num class isn't available in this module.
286         
287 \begin{code}
288 instance  Bounded Int where
289     minBound =  minInt
290     maxBound =  maxInt
291
292 instance  Enum Int  where
293     succ x  
294        | x == maxBound  = error "Prelude.Enum.succ{Int}: tried to take `succ' of maxBound"
295        | otherwise      = x `plusInt` oneInt
296     pred x
297        | x == minBound  = error "Prelude.Enum.pred{Int}: tried to take `pred' of minBound"
298        | otherwise      = x `minusInt` oneInt
299
300     toEnum   x = x
301     fromEnum x = x
302
303     {-# INLINE enumFrom #-}
304     enumFrom (I# x) = build (\ c n -> eftIntFB c n x 2147483647#)
305         -- Blarg: technically I guess enumFrom isn't strict!
306
307     {-# INLINE enumFromTo #-}
308     enumFromTo (I# x) (I# y) = build (\ c n -> eftIntFB c n x y)
309
310     {-# INLINE enumFromThen #-}
311     enumFromThen (I# x1) (I# x2) = build (\ c n -> efdIntFB c n x1 x2)
312
313     {-# INLINE enumFromThenTo #-}
314     enumFromThenTo (I# x1) (I# x2) (I# y) = build (\ c n -> efdtIntFB c n x1 x2 y)
315
316 {-# INLINE eftIntFB #-}
317 eftIntFB c n x y | x ># y    = n        
318                  | otherwise = go x
319                  where
320                    go x = I# x `c` if x ==# y then n else go (x +# 1#)
321                         -- Watch out for y=maxBound; hence ==, not >
322         -- Be very careful not to have more than one "c"
323         -- so that when eftInfFB is inlined we can inline
324         -- whatver is bound to "c"
325
326 eftIntList x y | x ># y    = []
327                | otherwise = go x
328                where
329                  go x = I# x : if x ==# y then [] else go (x +# 1#)
330
331
332 -- For enumFromThenTo we give up on inlining; so we don't worry
333 -- about duplicating occurrences of "c"
334 efdtIntFB c n x1 x2 y
335   | delta >=# 0# = if x1 ># y then n else go_up_int_fb c n x1 delta lim
336   | otherwise    = if x1 <# y then n else go_dn_int_fb c n x1 delta lim 
337   where
338     delta = x2 -# x1
339     lim   = y -# delta
340
341 efdtIntList x1 x2 y
342   | delta >=# 0# = if x1 ># y then [] else go_up_int_list x1 delta lim
343   | otherwise    = if x1 <# y then [] else go_dn_int_list x1 delta lim
344   where
345     delta = x2 -# x1
346     lim   = y -# delta
347
348 efdIntFB c n x1 x2
349   | delta >=# 0# = go_up_int_fb c n x1 delta (  2147483647#  -# delta)
350   | otherwise    = go_dn_int_fb c n x1 delta ((-2147483648#) -# delta)
351   where
352     delta = x2 -# x1
353
354 efdIntList x1 x2
355   | delta >=# 0# = go_up_int_list x1 delta (  2147483647#  -# delta)
356   | otherwise    = go_dn_int_list x1 delta ((-2147483648#) -# delta)
357   where
358     delta = x2 -# x1
359
360 -- In all of these, the (x +# delta) is guaranteed not to overflow
361
362 go_up_int_fb c n x delta lim
363   = go_up x
364   where
365     go_up x | x ># lim  = I# x `c` n
366             | otherwise = I# x `c` go_up (x +# delta)
367
368 go_dn_int_fb c n x delta lim 
369   = go_dn x
370   where
371     go_dn x | x <# lim  = I# x `c` n
372             | otherwise = I# x `c` go_dn (x +# delta)
373
374 go_up_int_list x delta lim
375   = go_up x
376   where
377     go_up x | x ># lim  = [I# x]
378             | otherwise = I# x : go_up (x +# delta)
379
380 go_dn_int_list x delta lim 
381   = go_dn x
382   where
383     go_dn x | x <# lim  = [I# x]
384             | otherwise = I# x : go_dn (x +# delta)
385
386
387 {-# RULES
388 "eftIntList"    eftIntFB  (:) [] = eftIntList
389 "efdIntList"    efdIntFB  (:) [] = efdIntList
390 "efdtIntList"   efdtIntFB (:) [] = efdtIntList
391  #-}
392 \end{code}
393