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