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