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