[project @ 1999-12-20 10:34:27 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
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) = build (\ c n -> eftCharFB c n (ord# x) 255#)
195         -- Blarg: technically I guess enumFrom isn't strict!
196
197     {-# INLINE enumFromTo #-}
198     enumFromTo (C# x) (C# y) = build (\ c n -> eftCharFB c n (ord# x) (ord# y))
199
200     {-# INLINE enumFromThen #-}
201     enumFromThen (C# x1) (C# x2) = build (\ c n -> efdCharFB c n (ord# x1) (ord# x2))
202
203     {-# INLINE enumFromThenTo #-}
204     enumFromThenTo (C# x1) (C# x2) (C# y) = build (\ c n -> efdtCharFB c n (ord# x1) (ord# x2) (ord# y))
205
206 -- We can do better than for Ints because we don't
207 -- have hassles about arithmetic overflow at maxBound
208 {-# INLINE eftCharFB #-}
209 eftCharFB c n x y = go x
210                  where
211                     go x | x ># y    = n
212                          | otherwise = C# (chr# x) `c` go (x +# 1#)
213
214 eftCharList x y | x ># y    = [] 
215                 | otherwise = C# (chr# x) : eftCharList (x +# 1#) y
216
217
218 -- For enumFromThenTo we give up on inlining
219 efdCharFB c n x1 x2
220   | delta >=# 0# = go_up_char_fb c n x1 delta 255#
221   | otherwise    = go_dn_char_fb c n x1 delta 0#
222   where
223     delta = x2 -# x1
224
225 efdCharList x1 x2
226   | delta >=# 0# = go_up_char_list x1 delta 255#
227   | otherwise    = go_dn_char_list x1 delta 0#
228   where
229     delta = x2 -# x1
230
231 efdtCharFB c n x1 x2 lim
232   | delta >=# 0# = go_up_char_fb c n x1 delta lim
233   | otherwise    = go_dn_char_fb c n x1 delta lim
234   where
235     delta = x2 -# x1
236
237 efdtCharList x1 x2 lim
238   | delta >=# 0# = go_up_char_list x1 delta lim
239   | otherwise    = go_dn_char_list x1 delta lim
240   where
241     delta = x2 -# x1
242
243 go_up_char_fb c n x delta lim
244   = go_up x
245   where
246     go_up x | x ># lim  = n
247             | otherwise = C# (chr# x) `c` go_up (x +# delta)
248
249 go_dn_char_fb c n x delta lim
250   = go_dn x
251   where
252     go_dn x | x <# lim  = n
253             | otherwise = C# (chr# x) `c` go_dn (x +# delta)
254
255 go_up_char_list x delta lim
256   = go_up x
257   where
258     go_up x | x ># lim  = []
259             | otherwise = C# (chr# x) : go_up (x +# delta)
260
261 go_dn_char_list x delta lim
262   = go_dn x
263   where
264     go_dn x | x <# lim  = []
265             | otherwise = C# (chr# x) : go_dn (x +# delta)
266
267
268 {-# RULES
269 "eftCharList"   eftCharFB  (:) [] = eftCharList
270 "efdCharList"   efdCharFB  (:) [] = efdCharList
271 "efdtCharList"  efdtCharFB (:) [] = efdtCharList
272  #-}
273 \end{code}
274
275
276 %*********************************************************
277 %*                                                      *
278 \subsection{Type @Int@}
279 %*                                                      *
280 %*********************************************************
281
282 Be careful about these instances.  
283         (a) remember that you have to count down as well as up e.g. [13,12..0]
284         (b) be careful of Int overflow
285         (c) remember that Int is bounded, so [1..] terminates at maxInt
286
287 Also NB that the Num class isn't available in this module.
288         
289 \begin{code}
290 instance  Bounded Int where
291     minBound =  minInt
292     maxBound =  maxInt
293
294 instance  Enum Int  where
295     succ x  
296        | x == maxBound  = error "Prelude.Enum.succ{Int}: tried to take `succ' of maxBound"
297        | otherwise      = x `plusInt` oneInt
298     pred x
299        | x == minBound  = error "Prelude.Enum.pred{Int}: tried to take `pred' of minBound"
300        | otherwise      = x `minusInt` oneInt
301
302     toEnum   x = x
303     fromEnum x = x
304
305     {-# INLINE enumFrom #-}
306     enumFrom (I# x) = build (\ c n -> eftIntFB c n x 2147483647#)
307         -- Blarg: technically I guess enumFrom isn't strict!
308
309     {-# INLINE enumFromTo #-}
310     enumFromTo (I# x) (I# y) = build (\ c n -> eftIntFB c n x y)
311
312     {-# INLINE enumFromThen #-}
313     enumFromThen (I# x1) (I# x2) = build (\ c n -> efdIntFB c n x1 x2)
314
315     {-# INLINE enumFromThenTo #-}
316     enumFromThenTo (I# x1) (I# x2) (I# y) = build (\ c n -> efdtIntFB c n x1 x2 y)
317
318 {-# INLINE eftIntFB #-}
319 eftIntFB c n x y | x ># y    = n        
320                  | otherwise = go x
321                  where
322                    go x = I# x `c` if x ==# y then n else go (x +# 1#)
323                         -- Watch out for y=maxBound; hence ==, not >
324         -- Be very careful not to have more than one "c"
325         -- so that when eftInfFB is inlined we can inline
326         -- whatver is bound to "c"
327
328 eftIntList x y | x ># y    = []
329                | otherwise = go x
330                where
331                  go x = I# x : if x ==# y then [] else go (x +# 1#)
332
333
334 -- For enumFromThenTo we give up on inlining; so we don't worry
335 -- about duplicating occurrences of "c"
336 efdtIntFB c n x1 x2 y
337   | delta >=# 0# = if x1 ># y then n else go_up_int_fb c n x1 delta lim
338   | otherwise    = if x1 <# y then n else go_dn_int_fb c n x1 delta lim 
339   where
340     delta = x2 -# x1
341     lim   = y -# delta
342
343 efdtIntList x1 x2 y
344   | delta >=# 0# = if x1 ># y then [] else go_up_int_list x1 delta lim
345   | otherwise    = if x1 <# y then [] else go_dn_int_list x1 delta lim
346   where
347     delta = x2 -# x1
348     lim   = y -# delta
349
350 efdIntFB c n x1 x2
351   | delta >=# 0# = go_up_int_fb c n x1 delta (  2147483647#  -# delta)
352   | otherwise    = go_dn_int_fb c n x1 delta ((-2147483648#) -# delta)
353   where
354     delta = x2 -# x1
355
356 efdIntList x1 x2
357   | delta >=# 0# = go_up_int_list x1 delta (  2147483647#  -# delta)
358   | otherwise    = go_dn_int_list x1 delta ((-2147483648#) -# delta)
359   where
360     delta = x2 -# x1
361
362 -- In all of these, the (x +# delta) is guaranteed not to overflow
363
364 go_up_int_fb c n x delta lim
365   = go_up x
366   where
367     go_up x | x ># lim  = I# x `c` n
368             | otherwise = I# x `c` go_up (x +# delta)
369
370 go_dn_int_fb c n x delta lim 
371   = go_dn x
372   where
373     go_dn x | x <# lim  = I# x `c` n
374             | otherwise = I# x `c` go_dn (x +# delta)
375
376 go_up_int_list x delta lim
377   = go_up x
378   where
379     go_up x | x ># lim  = [I# x]
380             | otherwise = I# x : go_up (x +# delta)
381
382 go_dn_int_list x delta lim 
383   = go_dn x
384   where
385     go_dn x | x <# lim  = [I# x]
386             | otherwise = I# x : go_dn (x +# delta)
387
388
389 {-# RULES
390 "eftIntList"    eftIntFB  (:) [] = eftIntList
391 "efdIntList"    efdIntFB  (:) [] = efdIntList
392 "efdtIntList"   efdtIntFB (:) [] = efdtIntList
393  #-}
394 \end{code}
395