[project @ 1999-01-21 20:15:30 by sof]
authorsof <unknown>
Thu, 21 Jan 1999 20:15:32 +0000 (20:15 +0000)
committersof <unknown>
Thu, 21 Jan 1999 20:15:32 +0000 (20:15 +0000)
Enum instances updated to comply with the behaviour that
Haskell 98 specifies. Notable changes,

  * [a..b] is not the empty list when a>b any longer.
  * [x..] and [x,y..] for Enum Int are now bounded lists.

The first change is might be worth bearing in mind when converting
1.4 code to Haskell 98; functions may have made use of the
old behaviour.

ghc/lib/std/PrelBase.lhs
ghc/lib/std/PrelBounded.lhs
ghc/lib/std/PrelHandle.lhs
ghc/lib/std/PrelNum.lhs
ghc/lib/std/PrelNumExtra.lhs

index 48dc8cf..1d6d69d 100644 (file)
@@ -325,10 +325,10 @@ instance Ord () where
     compare () () = EQ
 
 instance Enum () where
-    succ x      = x
-    pred x      = x
+    succ x      = error "Prelude.Enum.succ{()}: not possible"
+    pred x      = error "Prelude.Enum.pred{()}: not possible"
     toEnum 0    = ()
-    toEnum _   = error "Prelude.Enum.().toEnum: argument not 0"
+    toEnum _   = error "Prelude.Enum.toEnum{()}: argument not 0"
     fromEnum () = 0
     enumFrom ()        = [()]
     enumFromThen () ()         = [()]
@@ -347,7 +347,7 @@ instance  Show ()  where
 %*********************************************************
 
 \begin{code}
-data Ordering = LT | EQ | GT   deriving (Eq, Ord, Enum, Bounded, Show {- Read -})
+data Ordering = LT | EQ | GT   deriving (Eq, Ord, Enum, Bounded, Show {- in PrelRead: Read -})
 \end{code}
 
 
@@ -365,17 +365,19 @@ data Char = C# Char#      deriving (Eq, Ord)
 instance  Enum Char  where
     succ     c@(C# c#)
        | not (ord# c# ==# 255#) = C# (chr# (ord# c# +# 1#))
-       | otherwise             = error ("Prelude.Enum{Char}.succ: out of range " ++ show c)
+       | otherwise             = error ("Prelude.Enum.succ{Char}: tried to take `succ' of maxBound")
     pred     c@(C# c#)
        | not (ord# c# ==# 0#)   = C# (chr# (ord# c# -# 1#))
-       | otherwise             = error ("Prelude.Enum{Char}.succ: out of range " ++ show c)
+       | otherwise             = error ("Prelude.Enum.pred{Char}: tried to to take `pred' of minBound")
 
     toEnum   (I# i) | i >=# 0# && i <=# 255# =  C# (chr# i)
-                   | otherwise = error ("Prelude.Enum.Char.toEnum:out of range: " ++ show (I# i))
-    fromEnum (C# c)            =  I# (ord# c)
+                   | otherwise = error ("Prelude.Enum.toEnum{Char}: out of range: " ++ show (I# i))
+    fromEnum (C# c) =  I# (ord# c)
 
-    enumFrom   (C# c)         =  efttCh (ord# c)  1#   (># 255#)
-    enumFromTo (C# c1) (C# c2) = efttCh (ord# c1) 1#  (># (ord# c2))
+    enumFrom   (C# c)         = efttCh (ord# c)  1#   (># 255#)
+    enumFromTo (C# c1) (C# c2) 
+        | c1 `leChar#` c2 = efttCh (ord# c1) 1#               (># (ord# c2))
+        | otherwise       = efttCh (ord# c1) (negateInt# 1#)  (<# (ord# c2))
 
     enumFromThen (C# c1) (C# c2)
        | c1 `leChar#` c2 = efttCh (ord# c1) (ord# c2 -# ord# c1) (># 255#)
@@ -432,6 +434,9 @@ isUpper c           =  c >= 'A' && c <= 'Z' ||
 isLower c              =  c >= 'a' && c <= 'z' ||
                            c >= '\xDF' && c <= '\xF6' ||
                            c >= '\xF8' && c <= '\xFF'
+isAsciiLower c          =  c >= 'a' && c <= 'z'
+isAsciiUpper c          =  c >= 'A' && c <= 'Z'
+
 isAlpha c              =  isLower c || isUpper c
 isDigit c              =  c >= '0' && c <= '9'
 isOctDigit c           =  c >= '0' && c <= '7'
@@ -442,15 +447,23 @@ isAlphaNum c              =  isAlpha c || isDigit c
 -- Case-changing operations
 
 toUpper, toLower       :: Char -> Char
-toUpper c 
+toUpper c@(C# c#)
+  | isAsciiLower c    = C# (chr# (ord# c# -# 32#))
+  | isAscii c         = c
+    -- fall-through to the slower stuff.
   | isLower c  && c /= '\xDF' && c /= '\xFF'
-  =  toEnum (fromEnum c - fromEnum 'a' + fromEnum 'A')
-  | otherwise  
-  =  c
+  = toEnum (fromEnum c - fromEnum 'a' + fromEnum 'A')
+  | otherwise
+  = c
+
 
-toLower c | isUpper c  =  toEnum (fromEnum c - fromEnum 'A' 
+
+toLower c@(C# c#)
+  | isAsciiUpper c = C# (chr# (ord# c# +# 32#))
+  | isAscii c      = c
+  | isUpper c     =  toEnum (fromEnum c - fromEnum 'A' 
                                               + fromEnum 'a')
-         | otherwise   =  c
+  | otherwise     =  c
 
 asciiTab :: [String]
 asciiTab = -- Using an array drags in the array module.  listArray ('\NUL', ' ')
@@ -489,20 +502,35 @@ compareInt :: Int -> Int -> Ordering
                           | x ==# y   = EQ
                           | otherwise = GT
 
+instance  Bounded Int where
+    minBound =  -2147483648            -- GHC <= 2.09 had this at -2147483647
+    maxBound =   2147483647
+
 instance  Enum Int  where
-    succ x     = x+1
-    pred x     = x-1
+    succ x  
+       | x == maxBound  = error "Prelude.Enum.succ{Int}: tried to take `succ' of maxBound"
+       | otherwise      = x+1
+    pred x
+       | x == minBound  = error "Prelude.Enum.pred{Int}: tried to take `pred' of minBound"
+       | otherwise      = x-1
+
     toEnum   x = x
     fromEnum x = x
 
 #ifndef USE_FOLDR_BUILD
-    enumFrom     (I# c)                 = eftInt c  1#
-    enumFromTo   (I# c1) (I# c2) = efttInt c1 1#  (># c2)
-    enumFromThen (I# c1) (I# c2) = eftInt c1 (c2 -# c1)
+    enumFrom     (I# c)        = efttInt True c 1# (\ _ -> False)
+
+    enumFromTo   (I# c1) (I# c2) 
+        | c1 <# c2  = efttInt True  c1 1#              (># c2)
+       | otherwise = efttInt False c1 (negateInt# 1#) (<# c2)
+
+    enumFromThen (I# c1) (I# c2) 
+        | c1 <# c2  = efttInt True  c1 (c2 -# c1) (\ _ -> False)
+       | otherwise = efttInt False c1 (c2 -# c1) (\ _ -> False)
 
     enumFromThenTo (I# c1) (I# c2) (I# c3)
-       | c1 <=# c2 = efttInt c1 (c2 -# c1) (># c3)
-       | otherwise = efttInt c1 (c2 -# c1) (<# c3)
+       | c1 <=# c2 = efttInt True  c1 (c2 -# c1) (># c3)
+       | otherwise = efttInt False c1 (c2 -# c1) (<# c3)
 
 #else
     {-# INLINE enumFrom #-}
@@ -513,19 +541,16 @@ instance  Enum Int  where
        let g x = if x <= y then x `c` g (x `plusInt` 1) else n in g x)
 #endif
 
-efttInt :: Int# -> Int# -> (Int# -> Bool) -> [Int]
-efttInt init step done
-  = go init
-  where
-    go now | done now  = []
-          | otherwise = I# now : go (now +# step)
-
-eftInt :: Int# -> Int# -> [Int]
-eftInt init step
-  = go init
+efttInt :: Bool -> Int# -> Int# -> (Int# -> Bool) -> [Int]
+efttInt increasing init step done = go init
   where
-    go now = I# now : go (now +# step)
-
+    go now 
+     | done now                     = []    
+     | increasing     && now ># nxt = [I# now] -- overflowed
+     | not increasing && now <# nxt = [I# now] -- underflowed
+     | otherwise                   = I# now : go nxt
+     where
+      nxt = now +# step
 
 instance  Num Int  where
     (+)           x y =  plusInt x y
index 3d1d0fd..de8699e 100644 (file)
@@ -20,7 +20,4 @@ instance  Bounded Char  where
     minBound =  '\0'
     maxBound =  '\255'
 
-instance  Bounded Int where
-    minBound =  -2147483648            -- GHC <= 2.09 had this at -2147483647
-    maxBound =   2147483647
 \end{code}
index 139594d..caa8c50 100644 (file)
@@ -313,6 +313,8 @@ openFileEx f m = do
 #ifndef __CONCURRENT_HASKELL__
     file_flags = file_flags'
 #else
+       -- See comment next to 'stderr' for why we leave
+       -- non-blocking off for now.
     file_flags = file_flags' {-+ 128  Don't block on I/O-}
 #endif
 
index 4f09ebd..5a835ad 100644 (file)
@@ -138,10 +138,10 @@ instance  Integral Int    where
     -- Following chks for zero divisor are non-standard (WDP)
     a `quot` b =  if b /= 0
                   then a `quotInt` b
-                  else error "Prelude.Integral{Int}.quot: divide by 0\n"
+                  else error "Prelude.Integral.quot{Int}: divide by 0"
     a `rem` b  =  if b /= 0
                   then a `remInt` b
-                  else error "Prelude.Integral{Int}.rem: divide by 0\n"
+                  else error "Prelude.Integral.rem{Int}: divide by 0"
 
     x `div` y = if x > 0 && y < 0      then quotInt (x-y-1) y
                else if x < 0 && y > 0  then quotInt (x-y+1) y
@@ -254,10 +254,10 @@ instance  Integral Integer where
     -- you get slightly better code if you let the compiler
     -- see them right here:
     n `quot` d =  if d /= 0 then q else 
-                    error "Prelude.Integral{Integer}.quot: divide by 0\n"  
+                    error "Prelude.Integral.quot{Integer}: divide by 0"  
                   where (q,_) = quotRem n d
     n `rem` d  =  if d /= 0 then r else 
-                    error "Prelude.Integral{Integer}.rem: divide by 0\n"  
+                    error "Prelude.Integral.rem{Integer}: divide by 0"  
                   where (_,r) = quotRem n d
     n `div` d  =  q  where (q,_) = divMod n d
     n `mod` d  =  r  where (_,r) = divMod n d
@@ -272,11 +272,15 @@ instance  Enum Integer  where
     toEnum n            =  toInteger n
     fromEnum n          =  toInt n
     enumFrom n           =  n : enumFrom (n + 1)
-    enumFromThen m n     =  en' m (n - m)
+    enumFromThen e1 e2   =  en' e1 (e2 - e1)
                            where en' a b = a : en' (a + b) b
-    enumFromTo n m       =  takeWhile (<= m) (enumFrom n)
-    enumFromThenTo n m p =  takeWhile (if m >= n then (<= p) else (>= p))
-                                     (enumFromThen n m)
+    enumFromTo n m
+      | n <= m           =  takeWhile (<= m) (enumFrom n)
+      | otherwise        =  takeWhile (>= m) (enumFromThen n (n-1))
+    enumFromThenTo n m p =  takeWhile pred   (enumFromThen n m)
+           where
+            pred | m >= n    = (<= p)
+                 | otherwise = (>= p)
 
 instance  Show Integer  where
     showsPrec   x = showSignedInteger x
index 5ba5ebd..8322e26 100644 (file)
@@ -384,6 +384,7 @@ instance  Enum Float  where
     toEnum         =  fromIntegral
     fromEnum       =  fromInteger . truncate   -- may overflow
     enumFrom      =  numericEnumFrom
+    enumFromTo     =  numericEnumFromTo
     enumFromThen   =  numericEnumFromThen
     enumFromThenTo =  numericEnumFromThenTo
 
@@ -396,13 +397,22 @@ instance  Enum Double  where
     enumFromThen   =  numericEnumFromThen
     enumFromThenTo =  numericEnumFromThenTo
 
-numericEnumFrom                :: (Real a) => a -> [a]
-numericEnumFromThen    :: (Real a) => a -> a -> [a]
-numericEnumFromThenTo   :: (Real a) => a -> a -> a -> [a]
+numericEnumFrom                :: (Fractional a) => a -> [a]
 numericEnumFrom                =  iterate (+1)
+
+numericEnumFromThen    :: (Fractional a) => a -> a -> [a]
 numericEnumFromThen n m        =  iterate (+(m-n)) n
-numericEnumFromThenTo n m p = takeWhile (if m >= n then (<= p) else (>= p))
-                                     (numericEnumFromThen n m)
+
+numericEnumFromTo       :: (Ord a, Fractional a) => a -> a -> [a]
+numericEnumFromTo n m   = takeWhile (<= m + 1/2) (numericEnumFrom n)
+
+numericEnumFromThenTo   :: (Ord a, Fractional a) => a -> a -> a -> [a]
+numericEnumFromThenTo e1 e2 e3 = takeWhile pred (numericEnumFromThen e1 e2)
+                               where
+                                mid = (e2 - e1) / 2
+                                pred | e2 > e1   = (<= e3 + mid)
+                                     | otherwise = (>= e3 + mid)
+                                     
 \end{code}
 
 @approxRational@, applied to two real fractional numbers x and epsilon,
@@ -472,11 +482,23 @@ instance  (Integral a)    => RealFrac (Ratio a)  where
 instance  (Integral a) => Enum (Ratio a)  where
     succ x             =  x + 1
     pred x             =  x - 1
-    enumFrom           =  iterate ((+)1)
-    enumFromThen n m   =  iterate ((+)(m-n)) n
+
     toEnum n            =  fromIntegral n :% 1
     fromEnum            =  fromInteger . truncate
 
+    enumFrom           =  bounded_iterator True (1)
+    enumFromThen n m   =  bounded_iterator (diff >= 0) diff n 
+                         where diff = m - n
+
+
+bounded_iterator :: (Ord a, Num a) => Bool -> a -> a -> [a]
+bounded_iterator inc step v 
+   | inc      && v > new_v = [v]  -- oflow
+   | not inc  && v < new_v = [v]  -- uflow
+   | otherwise             = v : bounded_iterator inc step new_v
+  where
+   new_v = v + step
+
 ratio_prec :: Int
 ratio_prec = 7