+% -----------------------------------------------------------------------------
+% $Id: PrelEnum.lhs,v 1.14 2001/07/24 06:31:35 ken Exp $
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
+% (c) The University of Glasgow, 1992-2000
%
+
\section[PrelBounded]{Module @PrelBounded@}
Instances of Bounded for various datatypes.
module PrelEnum(
Bounded(..), Enum(..),
- enumFromBounded, enumFromThenBounded,
+ boundedEnumFrom, boundedEnumFromThen,
-- Instances for Bounded and Eum: (), Char, Int
import {-# SOURCE #-} PrelErr ( error )
import PrelBase
import PrelTup () -- To make sure we look for the .hi file
+
+default () -- Double isn't available yet
\end{code}
succ = toEnum . (`plusInt` oneInt) . fromEnum
pred = toEnum . (`minusInt` oneInt) . fromEnum
- enumFromTo n m = map toEnum [fromEnum n .. fromEnum m]
- enumFromThenTo n1 n2 m = map toEnum [fromEnum n1, fromEnum n2 .. fromEnum m]
+ enumFrom x = map toEnum [fromEnum x ..]
+ enumFromThen x y = map toEnum [fromEnum x, fromEnum y ..]
+ enumFromTo x y = map toEnum [fromEnum x .. fromEnum y]
+ enumFromThenTo x1 x2 y = map toEnum [fromEnum x1, fromEnum x2 .. fromEnum y]
-- Default methods for bounded enumerations
-enumFromBounded :: (Enum a, Bounded a) => a -> [a]
-enumFromBounded n = enumFromTo n maxBound
+boundedEnumFrom :: (Enum a, Bounded a) => a -> [a]
+boundedEnumFrom n = map toEnum [fromEnum n .. fromEnum (maxBound `asTypeOf` n)]
-enumFromThenBounded :: (Enum a, Bounded a) => a -> a -> [a]
-enumFromThenBounded n1 n2 = enumFromThenTo n1 n2 maxBound
+boundedEnumFromThen :: (Enum a, Bounded a) => a -> a -> [a]
+boundedEnumFromThen n1 n2
+ | i_n2 >= i_n1 = map toEnum [i_n1, i_n2 .. fromEnum (maxBound `asTypeOf` n1)]
+ | otherwise = map toEnum [i_n1, i_n2 .. fromEnum (minBound `asTypeOf` n1)]
+ where
+ i_n1 = fromEnum n1
+ i_n2 = fromEnum n2
\end{code}
maxBound = ()
instance Enum () where
- succ x = error "Prelude.Enum.().succ: bad argment"
- pred x = error "Prelude.Enum.().pred: bad argument"
+ succ _ = error "Prelude.Enum.().succ: bad argment"
+ pred _ = error "Prelude.Enum.().pred: bad argument"
toEnum x | x == zeroInt = ()
| otherwise = error "Prelude.Enum.().toEnum: bad argument"
fromEnum True = oneInt
-- Use defaults for the rest
- enumFrom = enumFromBounded
- enumFromThen = enumFromThenBounded
+ enumFrom = boundedEnumFrom
+ enumFromThen = boundedEnumFromThen
\end{code}
%*********************************************************
toEnum n | n == zeroInt = LT
| n == oneInt = EQ
| n == twoInt = GT
- toEnum n = error "Prelude.Enum.Ordering.toEnum: bad argment"
+ toEnum _ = error "Prelude.Enum.Ordering.toEnum: bad argment"
fromEnum LT = zeroInt
fromEnum EQ = oneInt
fromEnum GT = twoInt
-- Use defaults for the rest
- enumFrom = enumFromBounded
- enumFromThen = enumFromThenBounded
+ enumFrom = boundedEnumFrom
+ enumFromThen = boundedEnumFromThen
\end{code}
%*********************************************************
\begin{code}
instance Bounded Char where
minBound = '\0'
- maxBound = '\255'
+ maxBound = '\x10FFFF'
instance Enum Char where
- succ c@(C# c#)
- | not (ord# c# ==# 255#) = C# (chr# (ord# c# +# 1#))
+ succ (C# c#)
+ | not (ord# c# ==# 0x10FFFF#) = C# (chr# (ord# c# +# 1#))
| otherwise = error ("Prelude.Enum.Char.succ: bad argument")
- pred c@(C# c#)
+ pred (C# c#)
| not (ord# c# ==# 0#) = C# (chr# (ord# c# -# 1#))
| otherwise = error ("Prelude.Enum.Char.pred: bad argument")
fromEnum = ord
{-# INLINE enumFrom #-}
- enumFrom (C# x) = build (\ c n -> eftCharFB c n (ord# x) 255#)
+ enumFrom (C# x) = eftChar (ord# x) 0x10FFFF#
-- Blarg: technically I guess enumFrom isn't strict!
{-# INLINE enumFromTo #-}
- enumFromTo (C# x) (C# y) = build (\ c n -> eftCharFB c n (ord# x) (ord# y))
-
+ enumFromTo (C# x) (C# y) = eftChar (ord# x) (ord# y)
+
{-# INLINE enumFromThen #-}
- enumFromThen (C# x1) (C# x2) = build (\ c n -> efdtCharFB c n (ord# x1) (ord# x2) 255#)
-
+ enumFromThen (C# x1) (C# x2) = efdChar (ord# x1) (ord# x2)
+
{-# INLINE enumFromThenTo #-}
- enumFromThenTo (C# x1) (C# x2) (C# y) = build (\ c n -> efdtCharFB c n (ord# x1) (ord# x2) (ord# y))
+ enumFromThenTo (C# x1) (C# x2) (C# y) = efdtChar (ord# x1) (ord# x2) (ord# y)
+
+eftChar = eftCharList
+efdChar = efdCharList
+efdtChar = efdtCharList
+
+
+{-# RULES
+"eftChar" forall x y. eftChar x y = build (\c n -> eftCharFB c n x y)
+"efdChar" forall x1 x2. efdChar x1 x2 = build (\ c n -> efdCharFB c n x1 x2)
+"efdtChar" forall x1 x2 l. efdtChar x1 x2 l = build (\ c n -> efdtCharFB c n x1 x2 l)
+"eftCharList" eftCharFB (:) [] = eftCharList
+"efdCharList" efdCharFB (:) [] = efdCharList
+"efdtCharList" efdtCharFB (:) [] = efdtCharList
+ #-}
+
-- We can do better than for Ints because we don't
-- have hassles about arithmetic overflow at maxBound
-- For enumFromThenTo we give up on inlining
-efdtCharFB c n x1 x2 y
- | delta >=# 0# = go_up x1
- | otherwise = go_dn x1
+efdCharFB c n x1 x2
+ | delta >=# 0# = go_up_char_fb c n x1 delta 0x10FFFF#
+ | otherwise = go_dn_char_fb c n x1 delta 0#
where
delta = x2 -# x1
- go_up x | x ># y = n
+
+efdCharList x1 x2
+ | delta >=# 0# = go_up_char_list x1 delta 0x10FFFF#
+ | otherwise = go_dn_char_list x1 delta 0#
+ where
+ delta = x2 -# x1
+
+efdtCharFB c n x1 x2 lim
+ | delta >=# 0# = go_up_char_fb c n x1 delta lim
+ | otherwise = go_dn_char_fb c n x1 delta lim
+ where
+ delta = x2 -# x1
+
+efdtCharList x1 x2 lim
+ | delta >=# 0# = go_up_char_list x1 delta lim
+ | otherwise = go_dn_char_list x1 delta lim
+ where
+ delta = x2 -# x1
+
+go_up_char_fb c n x delta lim
+ = go_up x
+ where
+ go_up x | x ># lim = n
| otherwise = C# (chr# x) `c` go_up (x +# delta)
- go_dn x | x <# y = n
+
+go_dn_char_fb c n x delta lim
+ = go_dn x
+ where
+ go_dn x | x <# lim = n
| otherwise = C# (chr# x) `c` go_dn (x +# delta)
-efdtCharList x1 x2 y
- | delta >=# 0# = go_up x1
- | otherwise = go_dn x1
+go_up_char_list x delta lim
+ = go_up x
where
- delta = x2 -# x1
- go_up x | x ># y = []
+ go_up x | x ># lim = []
| otherwise = C# (chr# x) : go_up (x +# delta)
- go_dn x | x <# y = []
- | otherwise = C# (chr# x) : go_dn (x +# delta)
-
-{-# RULES
-"eftCharList" eftCharFB (:) [] = eftCharList
-"efdtCharList" efdtCharFB (:) [] = efdtCharList
- #-}
+go_dn_char_list x delta lim
+ = go_dn x
+ where
+ go_dn x | x <# lim = []
+ | otherwise = C# (chr# x) : go_dn (x +# delta)
\end{code}
%* *
%*********************************************************
+Be careful about these instances.
+ (a) remember that you have to count down as well as up e.g. [13,12..0]
+ (b) be careful of Int overflow
+ (c) remember that Int is bounded, so [1..] terminates at maxInt
+
+Also NB that the Num class isn't available in this module.
+
\begin{code}
instance Bounded Int where
minBound = minInt
fromEnum x = x
{-# INLINE enumFrom #-}
- enumFrom (I# x) = build (\ c n -> eftIntFB c n x 2147483647#)
+ enumFrom (I# x) = case maxInt of I# y -> eftInt x y
-- Blarg: technically I guess enumFrom isn't strict!
{-# INLINE enumFromTo #-}
- enumFromTo (I# x) (I# y) = build (\ c n -> eftIntFB c n x y)
+ enumFromTo (I# x) (I# y) = eftInt x y
{-# INLINE enumFromThen #-}
- enumFromThen (I# x1) (I# x2) = build (\ c n -> efdIntFB c n x1 x2)
+ enumFromThen (I# x1) (I# x2) = efdInt x1 x2
{-# INLINE enumFromThenTo #-}
- enumFromThenTo (I# x1) (I# x2) (I# y) = build (\ c n -> efdtIntFB c n x1 x2 y)
+ enumFromThenTo (I# x1) (I# x2) (I# y) = efdtInt x1 x2 y
+
+eftInt = eftIntList
+efdInt = efdIntList
+efdtInt = efdtIntList
+
+{-# RULES
+"eftInt" forall x y. eftInt x y = build (\ c n -> eftIntFB c n x y)
+"efdInt" forall x1 x2. efdInt x1 x2 = build (\ c n -> efdIntFB c n x1 x2)
+"efdtInt" forall x1 x2 l. efdtInt x1 x2 l = build (\ c n -> efdtIntFB c n x1 x2 l)
+
+"eftIntList" eftIntFB (:) [] = eftIntList
+"efdIntList" efdIntFB (:) [] = efdIntList
+"efdtIntList" efdtIntFB (:) [] = efdtIntList
+ #-}
+
{-# INLINE eftIntFB #-}
eftIntFB c n x y | x ># y = n
-- For enumFromThenTo we give up on inlining; so we don't worry
-- about duplicating occurrences of "c"
efdtIntFB c n x1 x2 y
- | delta >=# 0# = if x1 ># y then n else go_up x1
- | otherwise = if x1 <# y then n else go_dn x1
+ | delta >=# 0# = if x1 ># y then n else go_up_int_fb c n x1 delta lim
+ | otherwise = if x1 <# y then n else go_dn_int_fb c n x1 delta lim
where
delta = x2 -# x1
- go_up x | y -# x <# delta = I# x `c` n
- | otherwise = I# x `c` go_up (x +# delta)
- go_dn x | y -# x ># delta = I# x `c` n
- | otherwise = I# x `c` go_dn (x +# delta)
+ lim = y -# delta
efdtIntList x1 x2 y
- | delta >=# 0# = if x1 ># y then [] else go_up x1
- | otherwise = if x1 <# y then [] else go_dn x1
+ | delta >=# 0# = if x1 ># y then [] else go_up_int_list x1 delta lim
+ | otherwise = if x1 <# y then [] else go_dn_int_list x1 delta lim
where
delta = x2 -# x1
- go_up x | y -# x <# delta = [I# x]
- | otherwise = I# x : go_up (x +# delta)
- go_dn x | y -# x ># delta = [I# x]
- | otherwise = I# x : go_dn (x +# delta)
+ lim = y -# delta
efdIntFB c n x1 x2
- | delta >=# 0# = go_up x1
- | otherwise = go_dn x1
+ | delta >=# 0# = case maxInt of I# y -> go_up_int_fb c n x1 delta (y -# delta)
+ | otherwise = case minInt of I# y -> go_dn_int_fb c n x1 delta (y -# delta)
where
delta = x2 -# x1
- go_up x | 2147483647# -# x <# delta = I# x `c` n
- | otherwise = I# x `c` go_up (x +# delta)
- go_dn x | (-2147483648#) -# x ># delta = I# x `c` n
- | otherwise = I# x `c` go_dn (x +# delta)
efdIntList x1 x2
- | delta >=# 0# = go_up x1
- | otherwise = go_dn x1
+ | delta >=# 0# = case maxInt of I# y -> go_up_int_list x1 delta (y -# delta)
+ | otherwise = case minInt of I# y -> go_dn_int_list x1 delta (y -# delta)
where
delta = x2 -# x1
- go_up x | 2147483647# -# x <# delta = [I# x]
- | otherwise = I# x : go_up (x +# delta)
- go_dn x | (-2147483648#) -# x ># delta = [I# x]
- | otherwise = I# x : go_dn (x +# delta)
+-- In all of these, the (x +# delta) is guaranteed not to overflow
-{-# RULES
-"eftIntList" eftIntFB (:) [] = eftIntList
-"efdIntList" efdIntFB (:) [] = efdIntList
-"efdtIntList" efdtIntFB (:) [] = efdtIntList
- #-}
+go_up_int_fb c n x delta lim
+ = go_up x
+ where
+ go_up x | x ># lim = I# x `c` n
+ | otherwise = I# x `c` go_up (x +# delta)
+
+go_dn_int_fb c n x delta lim
+ = go_dn x
+ where
+ go_dn x | x <# lim = I# x `c` n
+ | otherwise = I# x `c` go_dn (x +# delta)
+
+go_up_int_list x delta lim
+ = go_up x
+ where
+ go_up x | x ># lim = [I# x]
+ | otherwise = I# x : go_up (x +# delta)
+
+go_dn_int_list x delta lim
+ = go_dn x
+ where
+ go_dn x | x <# lim = [I# x]
+ | otherwise = I# x : go_dn (x +# delta)
\end{code}