[project @ 1999-05-18 14:59:04 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         = enumFromTo n maxBound
52
53 enumFromThenBounded :: (Enum a, Bounded a) => a -> a -> [a]
54 enumFromThenBounded n1 n2 = enumFromThenTo n1 n2 maxBound
55 \end{code}
56
57
58 %*********************************************************
59 %*                                                      *
60 \subsection{Tuples}
61 %*                                                      *
62 %*********************************************************
63
64 \begin{code}
65 instance Bounded () where
66     minBound = ()
67     maxBound = ()
68
69 instance Enum () where
70     succ x      = error "Prelude.Enum.().succ: bad argment"
71     pred x      = error "Prelude.Enum.().pred: bad argument"
72
73     toEnum x | x == zeroInt = ()
74              | otherwise    = error "Prelude.Enum.().toEnum: bad argument"
75
76     fromEnum () = zeroInt
77     enumFrom ()         = [()]
78     enumFromThen () ()  = [()]
79     enumFromTo () ()    = [()]
80     enumFromThenTo () () () = [()]
81 \end{code}
82
83 \begin{code}
84 instance (Bounded a, Bounded b) => Bounded (a,b) where
85    minBound = (minBound, minBound)
86    maxBound = (maxBound, maxBound)
87
88 instance (Bounded a, Bounded b, Bounded c) => Bounded (a,b,c) where
89    minBound = (minBound, minBound, minBound)
90    maxBound = (maxBound, maxBound, maxBound)
91
92 instance (Bounded a, Bounded b, Bounded c, Bounded d) => Bounded (a,b,c,d) where
93    minBound = (minBound, minBound, minBound, minBound)
94    maxBound = (maxBound, maxBound, maxBound, maxBound)
95 \end{code}
96
97
98 %*********************************************************
99 %*                                                      *
100 \subsection{Type @Bool@}
101 %*                                                      *
102 %*********************************************************
103
104 \begin{code}
105 instance Bounded Bool where
106   minBound = False
107   maxBound = True
108
109 instance Enum Bool where
110   succ False = True
111   succ True  = error "Prelude.Enum.Bool.succ: bad argment"
112
113   pred True  = False
114   pred False  = error "Prelude.Enum.Bool.pred: bad argment"
115
116   toEnum n | n == zeroInt = False
117            | n == oneInt  = True
118            | otherwise    = error "Prelude.Enum.Bool.toEnum: bad argment"
119
120   fromEnum False = zeroInt
121   fromEnum True  = oneInt
122
123   -- Use defaults for the rest
124   enumFrom     = enumFromBounded
125   enumFromThen = enumFromThenBounded
126 \end{code}
127
128 %*********************************************************
129 %*                                                      *
130 \subsection{Type @Ordering@}
131 %*                                                      *
132 %*********************************************************
133
134 \begin{code}
135 instance Bounded Ordering where
136   minBound = LT
137   maxBound = GT
138
139 instance Enum Ordering where
140   succ LT = EQ
141   succ EQ = GT
142   succ GT = error "Prelude.Enum.Ordering.succ: bad argment"
143
144   pred GT = EQ
145   pred EQ = LT
146   pred LT = error "Prelude.Enum.Ordering.pred: bad argment"
147
148   toEnum n | n == zeroInt = LT
149            | n == oneInt  = EQ
150            | n == twoInt  = GT
151   toEnum n = error "Prelude.Enum.Ordering.toEnum: bad argment"
152
153   fromEnum LT = zeroInt
154   fromEnum EQ = oneInt
155   fromEnum GT = twoInt
156
157   -- Use defaults for the rest
158   enumFrom     = enumFromBounded
159   enumFromThen = enumFromThenBounded
160 \end{code}
161
162 %*********************************************************
163 %*                                                      *
164 \subsection{Type @Char@}
165 %*                                                      *
166 %*********************************************************
167
168 \begin{code}
169 instance  Bounded Char  where
170     minBound =  '\0'
171     maxBound =  '\255'
172
173 instance  Enum Char  where
174     succ     c@(C# c#)
175        | not (ord# c# ==# 255#) = C# (chr# (ord# c# +# 1#))
176        | otherwise              = error ("Prelude.Enum.Char.succ: bad argument")
177     pred     c@(C# c#)
178        | not (ord# c# ==# 0#)   = C# (chr# (ord# c# -# 1#))
179        | otherwise              = error ("Prelude.Enum.Char.pred: bad argument")
180
181     toEnum   = chr
182     fromEnum = ord
183
184     {-# INLINE enumFrom #-}
185     enumFrom (C# x) = build (\ c n -> eftCharFB c n (ord# x) 255#)
186         -- Blarg: technically I guess enumFrom isn't strict!
187
188     {-# INLINE enumFromTo #-}
189     enumFromTo (C# x) (C# y) = build (\ c n -> eftCharFB c n (ord# x) (ord# y))
190
191     {-# INLINE enumFromThen #-}
192     enumFromThen (C# x1) (C# x2) = build (\ c n -> efdtCharFB c n (ord# x1) (ord# x2) 255#)
193
194     {-# INLINE enumFromThenTo #-}
195     enumFromThenTo (C# x1) (C# x2) (C# y) = build (\ c n -> efdtCharFB c n (ord# x1) (ord# x2) (ord# y))
196
197 -- We can do better than for Ints because we don't
198 -- have hassles about arithmetic overflow at maxBound
199 {-# INLINE eftCharFB #-}
200 eftCharFB c n x y = go x
201                  where
202                     go x | x ># y    = n
203                          | otherwise = C# (chr# x) `c` go (x +# 1#)
204
205 eftCharList x y | x ># y    = [] 
206                 | otherwise = C# (chr# x) : eftCharList (x +# 1#) y
207
208
209 -- For enumFromThenTo we give up on inlining
210 efdtCharFB c n x1 x2 y
211   | delta >=# 0# = go_up x1
212   | otherwise    = go_dn x1
213   where
214     delta = x2 -# x1
215     go_up x | x ># y    = n
216             | otherwise = C# (chr# x) `c` go_up (x +# delta)
217     go_dn x | x <# y    = n
218             | otherwise = C# (chr# x) `c` go_dn (x +# delta)
219
220 efdtCharList x1 x2 y
221   | delta >=# 0# = go_up x1
222   | otherwise    = go_dn x1
223   where
224     delta = x2 -# x1
225     go_up x | x ># y    = []
226             | otherwise = C# (chr# x) : go_up (x +# delta)
227     go_dn x | x <# y    = []
228             | otherwise = C# (chr# x) : go_dn (x +# delta)
229
230
231 {-# RULES
232 "eftCharList"   eftCharFB  (:) [] = eftCharList
233 "efdtCharList"  efdtCharFB (:) [] = efdtCharList
234  #-}
235 \end{code}
236
237
238 %*********************************************************
239 %*                                                      *
240 \subsection{Type @Int@}
241 %*                                                      *
242 %*********************************************************
243
244 \begin{code}
245 instance  Bounded Int where
246     minBound =  minInt
247     maxBound =  maxInt
248
249 instance  Enum Int  where
250     succ x  
251        | x == maxBound  = error "Prelude.Enum.succ{Int}: tried to take `succ' of maxBound"
252        | otherwise      = x `plusInt` oneInt
253     pred x
254        | x == minBound  = error "Prelude.Enum.pred{Int}: tried to take `pred' of minBound"
255        | otherwise      = x `minusInt` oneInt
256
257     toEnum   x = x
258     fromEnum x = x
259
260     {-# INLINE enumFrom #-}
261     enumFrom (I# x) = build (\ c n -> eftIntFB c n x 2147483647#)
262         -- Blarg: technically I guess enumFrom isn't strict!
263
264     {-# INLINE enumFromTo #-}
265     enumFromTo (I# x) (I# y) = build (\ c n -> eftIntFB c n x y)
266
267     {-# INLINE enumFromThen #-}
268     enumFromThen (I# x1) (I# x2) = build (\ c n -> efdtIntFB c n x1 x2 2147483647#)
269
270     {-# INLINE enumFromThenTo #-}
271     enumFromThenTo (I# x1) (I# x2) (I# y) = build (\ c n -> efdtIntFB c n x1 x2 y)
272
273 {-# INLINE eftIntFB #-}
274 eftIntFB c n x y | x ># y    = n        
275                  | otherwise = go x
276                  where
277                    go x = I# x `c` if x ==# y then n else go (x +# 1#)
278                         -- Watch out for y=maxBound; hence ==, not >
279         -- Be very careful not to have more than one "c"
280         -- so that when eftInfFB is inlined we can inline
281         -- whatver is bound to "c"
282
283 eftIntList x y | x ># y    = []
284                | otherwise = go x
285                where
286                  go x = I# x : if x ==# y then [] else go (x +# 1#)
287
288
289 -- For enumFromThenTo we give up on inlining; so we don't worry
290 -- about duplicating occurrences of "c"
291 efdtIntFB c n x1 x2 y
292   | delta >=# 0# = if x1 ># y then n else go_up x1
293   | otherwise    = if x1 <# y then n else go_dn x1
294   where
295     delta = x2 -# x1
296     go_up x | y -# x <# delta = I# x `c` n
297             | otherwise       = I# x `c` go_up (x +# delta)
298     go_dn x | y -# x ># delta = I# x `c` n
299             | otherwise       = I# x `c` go_dn (x +# delta)
300
301 efdtIntList x1 x2 y
302   | delta >=# 0# = if x1 ># y then [] else go_up x1
303   | otherwise    = if x1 <# y then [] else go_dn x1
304   where
305     delta = x2 -# x1
306     go_up x | y -# x <# delta = [I# x]
307             | otherwise       = I# x : go_up (x +# delta)
308     go_dn x | y -# x ># delta = [I# x]
309             | otherwise       = I# x : go_dn (x +# delta)
310
311
312 {-# RULES
313 "eftIntList"    eftIntFB  (:) [] = eftIntList
314 "efdtIntList"   efdtIntFB (:) [] = efdtIntList
315  #-}
316 \end{code}
317