Mainly Enum
authorSimon Peyton Jones <simonpj@microsoft.com>
Fri, 2 Nov 2001 16:26:48 +0000 (16:26 +0000)
committerSimon Peyton Jones <simonpj@microsoft.com>
Fri, 2 Nov 2001 16:26:48 +0000 (16:26 +0000)
haskell98-bugs.html
libraries/code/Numeric.hs
report/basic.verb
report/derived.verb
report/exps.verb
report/preface-13.verb
report/syntax-lexical.verb

index 25c92a9..8c47085 100644 (file)
@@ -577,6 +577,17 @@ to and from strings." add the sentence:
 precedence of the enclosing context (see Appendix D.4)."
 (Clarification only.)
 
+<p><li> [Nov 2001] <strong> Page 79, Section 6.3.4, Class Enum; 
+Page 19, Section 3.10 Arithmetic Sequences; and Appendix D.2, Derived instances of Enum.</strong>
+<ul>
+<li> Move the specification of the <tt>Int</tt> and <tt>Integer</tt> instances of
+<tt>Enum</tt> 3.10 to 6.3.4.
+<li> Specify that, for bounded types, <tt>succ</tt> and <tt>pred</tt> should fail 
+when applied to <tt>maxBound</tt> and <tt>minBound</tt> resp.
+<li> Specify that the <tt>enum</tt> functions on numeric types are strict.
+<li> Remove material from D.2 so that it describes only the derived instances.
+</ul>
+
 <p><li><strong>Page 80, Section 6.3.6, Class Monad.</strong>
 Right at the bottom of the page, replace "However, for IO, the fail
 method invokes error." by "For IO, the fail method raises a user
@@ -855,30 +866,38 @@ doing it by hand.  In particular, an error will be raised if y is zero.
 <ul>
 <li> Add specifications for the functions exported by the Numeric library.
 
-<p><li>In <tt>formatRealFloat</tt>, add the following local definitions:
+<p><li>In <tt>formatRealFloat</tt>, replace the entire case alternative
+starting <tt>FFFixed</tt> with the following:
 <pre>
-    mk0 "" = "0"            -- Used to ensure we print 34.0, not 34.
-    mk0 s  = s              -- and 0.34 not .34
-    
-    mkdot0 "" = ""          -- Used to ensure we print 34, not 34.
-    mkdot0 s  = '.' : s
-</pre>
+          FFFixed ->
+            case decs of
+               Nothing         -- Always prints a decimal point
+                 | e > 0     -> take e (ds ++ repeat '0')
+                                ++ '.' : mk0 (drop e ds)
+                 | otherwise -> "0." ++ mk0 (replicate (-e) '0' ++ ds)
+              
+               Just dec ->  -- Print decimal point iff dec > 0
+                 let dec' = max dec 0 in
+                 if e >= 0 then
+                   let (ei, is') = roundTo base (dec' + e) is
+                       (ls, rs)  = splitAt (e+ei) 
+                                              (map intToDigit is')
+                   in  mk0 ls ++ mkdot0 rs
+                 else
+                   let (ei, is') = roundTo base dec' 
+                                           (replicate (-e) 0 ++ is)
+                       d : ds = map intToDigit 
+                                    (if ei > 0 then is' else 0:is')
+                   in  d : mkdot0 ds
+            where   
+              mk0 "" = "0"        -- Print 0.34, not .34
+              mk0 s  = s  
     
-<li> In the definition of <tt>formatRealFloat</tt>,
-<ul> 
-<li> in the definition of <tt>doFmt</tt>,
-<li> in the <tt>FFFixed</tt> branch of "<tt>case fmt of ...</tt>",
-<li> in the <tt>Nothing</tt> branch of "<tt>case  decs of ...</tt>",
-replace the entire branch "<tt>Nothing -> ...</tt>" with
-<pre>
-       Nothing | e >= 0    -> take e (ds ++ repeat '0') ++ mkdot0 (drop e ds)
-              | otherwise -> '0' : mkdot0 (replicate (-e) '0' ++ ds)
+              mkdot0 "" = ""       -- Print 34, not 34.
+              mkdot0 s  = '.' : s  -- when the format specifies no
+                                  -- digits after the decimal point
 </pre>
-<li> in the <tt>Just dec</tt> branch, replace "<tt>(if null ls then "0" else ls) ++ (if null rs then "" else '.' : rs)</tt>"
-by "<tt>mk0 ls ++ mkdot0 rs</tt>".
-
-<li> also in the <tt>Just dec</tt> branch, replace "<tt>d : '.' : ds</tt>" by "<tt>d : mkdot0 ds</tt>".
-</ul>
+(This fixes an infinite loop.)
 
 <p><li>In the definition of <tt>k</tt> in <tt>floatToDigits</tt> replace "<tt>fromInt e</tt>" by "<tt>fromIntegral e</tt>".
 (<tt>fromInt</tt> no longer exists.)
index 5b52c19..c61a2b9 100644 (file)
@@ -6,9 +6,10 @@ module Numeric(fromRat,
                showEFloat, showFFloat, showGFloat, showFloat, 
                readFloat, lexDigits) where
 
-import Char
-import Ratio
-import Array
+import Char   ( isDigit, isOctDigit, isHexDigit
+              , digitToInt, intToDigit )
+import Ratio  ( (%), numerator, denominator )
+import Array  ( (!), Array, array )
 
 -- This converts a rational to a floating.  This should be used in the
 -- Fractional instances of Float and Double.
@@ -116,7 +117,7 @@ readInt radix isDig digToInt s =
 
 -- Unsigned readers for various bases
 readDec, readOct, readHex :: (Integral a) => ReadS a
-readDec = readInt 10 isDigit digitToInt
+readDec = readInt 10 isDigit    digitToInt
 readOct = readInt  8 isOctDigit digitToInt
 readHex = readInt 16 isHexDigit digitToInt
 
@@ -149,12 +150,6 @@ formatRealFloat fmt decs x
         else 
             doFmt fmt (floatToDigits (toInteger base) x)
     
-    mk0 "" = "0"            -- Used to ensure we print 34.0, not 34.
-    mk0 s  = s              -- and 0.34 not .34
-    
-    mkdot0 "" = ""          -- Used to ensure we print 34, not 34.
-    mkdot0 s  = '.' : s
-    
     doFmt fmt (is, e)
       = let 
            ds = map intToDigit is
@@ -183,12 +178,12 @@ formatRealFloat fmt decs x
           
           FFFixed ->
             case decs of
-               Nothing 
+               Nothing         -- Always prints a decimal point
                  | e > 0     -> take e (ds ++ repeat '0')
-                                ++ mkdot0 (drop e ds)
-                 | otherwise -> '0' : mkdot0 (replicate (-e) '0' ++ ds)
+                                ++ '.' : mk0 (drop e ds)
+                 | otherwise -> "0." ++ mk0 (replicate (-e) '0' ++ ds)
               
-               Just dec ->
+               Just dec ->  -- Print decimal point iff dec > 0
                  let dec' = max dec 0 in
                  if e >= 0 then
                    let (ei, is') = roundTo base (dec' + e) is
@@ -201,6 +196,14 @@ formatRealFloat fmt decs x
                        d : ds = map intToDigit 
                                     (if ei > 0 then is' else 0:is')
                    in  d : mkdot0 ds
+            where   
+              mk0 "" = "0"        -- Print 0.34, not .34
+              mk0 s  = s  
+    
+              mkdot0 "" = ""       -- Print 34, not 34.
+              mkdot0 s  = '.' : s  -- when the format specifies no
+                                  -- digits after the decimal point
+    
 
 roundTo :: Int -> Int -> [Int] -> (Int, [Int])
 roundTo base d is = case f d is of
index 25d28dd..e87ca07 100644 (file)
@@ -1,5 +1,5 @@
 %
-% $Header: /home/cvs/root/haskell-report/report/basic.verb,v 1.9 2001/10/02 09:09:26 simonpj Exp $
+% $Header: /home/cvs/root/haskell-report/report/basic.verb,v 1.10 2001/11/02 16:26:48 simonpj Exp $
 %
 %**<title>The Haskell 98 Report: Basic Types and Classes</title>
 %*section 6
@@ -61,8 +61,9 @@ characters is defined in Section~\ref{lexemes-char}; character
 literals are nullary constructors in the datatype @Char@.  Type @Char@
 is an instance of the classes @Read@, @Show@, @Eq@, @Ord@, 
 @Enum@, and @Bounded@.  The @toEnum@ and @fromEnum@ functions,
-standard functions over bounded enumerations, map characters onto
-@Int@ values in the range "[ 0 , 2^{16}-1 ]".
+standard functions from class @Enum@, map characters to and from the
+@Int@ type.
+% @Int@ values in the range "[ 0 , 2^{16}-1 ]".
 
 Note that ASCII control characters each have several representations
 in character literals: numeric escapes, ASCII mnemonic escapes,
@@ -445,6 +446,7 @@ input from a string, which must be completely consumed by the input
 process.  The @lex@ function used by @read@ is also part of the Prelude.
 
 \subsubsection{The Enum Class}
+\label{enum-class}
 \indexclass{Enum}
 \indextt{toEnum}
 \indextt{fromEnum}
@@ -469,20 +471,88 @@ class  Enum a  where
 Class @Enum@ defines operations on sequentially ordered types.
 The functions @succ@ and @pred@ return the successor and predecessor,
 respectively, of a value.
-The @toEnum@ and @fromEnum@ functions map values from a type in
-@Enum@ onto @Int@.  These functions are not meaningful for all
-instances of @Enum@: floating
-point values or @Integer@ may not be mapped onto an @Int@.  A
-runtime error occurs if either @toEnum@ or @fromEnum@ is given a value
-not mappable to the result type.  
-
+The functions @fromEnum@ and @toEnum@ map values from a type in
+@Enum@ to and from @Int@.  
 The @enumFrom@... methods are used when translating arithmetic
-sequences (Section~\ref{arithmetic-sequences}), and should
-obey the specification given in there.
+sequences (Section~\ref{arithmetic-sequences}).
+
+Instances of @Enum@ may be derived for any enumeration type (types
+whose constructors have no fields); see Appendix~\ref{derived-appendix}.
+
+For any type that is an instance of class @Bounded@, the following
+should hold:
+\begin{itemize}
+\item The calls @succ maxBound@ and @pred minBound@ should result in
+a runtime error.
+
+\item @fromEnum@ and @toEnum@ should give a runtime error if the 
+result value is not representable in the result type.  For example,
+@toEnum 7 :: Bool@ is an error.
 
-Instances of @Enum@ may be derived
-for any enumeration type (types whose constructors have no fields).
-There are also @Enum@ instances for floats.  
+\item @enumFrom@ and @enumFromThen@ should be defined with 
+an implicit bound, thus:
+\bprog
+@
+  enumFrom     x   = enumFromTo     x maxBound
+  enumFromThen x y = enumFromThenTo x y bound
+    where
+      bound = if fromEnum y >= fromEnum x then
+                 maxBound
+              else
+                 minBound
+@
+\eprog
+\end{itemize}
+
+The following @Prelude@ types are instances of @Enum@: 
+\begin{itemize}
+\item Enumeration types: @()@, @Bool@, and @Ordering@. The
+semantics of these instances is given by Appendix~\ref{derived-appendix}.
+For example, @[LT..]@ is the list @[LT,EQ,GT]@.
+
+\item @Char@: the instance is given in Appendix~\ref{stdprelude}, based 
+on the primitive functions that convert between a @Char@ and an @Int@.
+For example, @enumFromTo 'a' 'z'@ denotes
+the list of lowercase letters in alphabetical order.
+
+\item Numeric types: @Int@, @Integer@, @Float@, @Double@.  The semantics
+of these instances is given next.
+\end{itemize}
+For all four numeric types, @succ@ adds 1; and @pred@ subtracts 1.
+The conversions @fromEnum@ and @toEnum@ convert between the type and @Int@.
+in the case of @Float@ and @Double@, the digits after the decimal point may be lost.
+It is implementation-dependent what @fromEnum@ returns when applied to 
+a value that is too large to fit in an @Int@.
+
+For the types @Int@ and @Integer@, the enumeration functions 
+have the following meaning:
+\begin{itemize}
+\item The sequence "@enumFrom@~e_1" is the list "@[@e_1@,@e_1+1@,@e_1+2@,@...@]@".
+
+\item The sequence "@enumFromThen@~e_1~e_2@" is the list "@[@e_1@,@e_1+i@,@e_1+2i@,@...@]@",
+where the increment, "i", is "e_2-e_1".  The increment may be zero or negative.
+If the increment is zero, all the list elements are the same.
+
+\item The sequence "@enumFromTo@~e_1~e_3" is 
+the list "@[@e_1@,@e_1+1@,@e_1+2@,@...e_3@]@".
+The list is empty if "e_1 > e_3".
+
+\item The sequence "@enumFromThenTo~e_1~e_2~e_3" 
+is the list "@[@e_1@,@e_1+i@,@e_1+2i@,@...e_3@]@",
+where the increment, "i", is "e_2-e_1".  If the increment 
+is positive or zero, the list terminates when the next element would
+be greater than "e_3"; the list is empty if "e_1 > e_3".
+If the increment is negative, the list terminates when the next element would
+be less than "e_3"; the list is empty if "e1 < e_3".
+\end{itemize}
+For @Float@ and @Double@, the semantics of the @enumFrom@ family is
+given by the rules for @Int@ above, except that the list terminates
+when the elements become greater than "e_3+i/2" for positive increment
+"i", or when they become less than "e_3+i/2" for negative "i".
+@fromEnum@ and @toEnum@ convert between the type and @Int@.
+
+For all four of these Prelude numeric types, all of the @enumFrom@ 
+family of functions are strict in all their arguments.
 
 \subsubsection{Class @Functor@}
 \indexclass{Functor}
index be91d23..c6fdf2c 100644 (file)
@@ -1,5 +1,5 @@
 %
-% $Header: /home/cvs/root/haskell-report/report/derived.verb,v 1.6 2001/08/14 07:48:24 simonpj Exp $
+% $Header: /home/cvs/root/haskell-report/report/derived.verb,v 1.7 2001/11/02 16:26:48 simonpj Exp $
 %
 % The paragraph describing the formats of standard representations might
 % be deleted, since the info is already in the Prelude.  
@@ -159,18 +159,7 @@ These examples illustrate this property:
 \subsection{Derived instances of @Enum@}
 \indexdi{Enum}
 Derived instance declarations for the class @Enum@ are only
-possible for enumerations.
-@Enum@ introduces the class methods
-@succ@\indextt{succ},
-@pred@\indextt{pred},
-@toEnum@\indextt{toEnum},
-@fromEnum@\indextt{fromEnum},
-@enumFrom@\indextt{enumFrom},
-@enumFromThen@\indextt{enumFromThen},
-@enumFromTo@\indextt{enumFromTo}, and
-@enumFromThenTo@\indextt{enumFromThenTo}.
-The latter four are used to define arithmetic sequences as described
-in Section~\ref{arithmetic-sequences}. 
+possible for enumerations (data types with only nullary constructors).
 
 The nullary constructors are assumed to be
 numbered left-to-right with the indices 0 through $n-1\/$.
@@ -180,18 +169,21 @@ an error to apply @succ@ to the maximum element, or @pred@ to the minimum
 element.
 
 The @toEnum@ and @fromEnum@ operators map enumerated values to and
-from the @Int@ type.
-
-@enumFrom n@ returns a list corresponding to the complete enumeration
-of @n@'s type starting at the value @n@.
-Similarly, @enumFromThen n n'@ is the enumeration starting at @n@, but
-with second element @n'@, and with subsequent elements generated at a
-spacing equal to the difference between @n@ and @n'@.
-@enumFromTo@ and @enumFromThenTo@ are as defined by the
-default class methods
-\index{default class method}
-for @Enum@ (see Figure~\ref{standard-classes},
-page~\pageref{standard-classes}).
+from the @Int@ type; @toEnum@ raises a runtime error if the @Int@ argument
+is not the index of one of the constructors.
+
+The definitions of the remaining methods are 
+\bprog
+@
+  enumFrom x           = enumFrom x maxBound
+  enumFromThen x y     = enumFromThenTo x y bound
+                      where
+                        bound | fromEnum y >= fromEnum x = maxBound
+                              | otherwise                = minBound
+  enumFromTo x y       = map toEnum [fromEnum x .. fromEnum y]
+  enumFromThenTo x y z = map toEnum [fromEnum x, fromEnum y .. fromEnum z]
+@
+\eprog
 For example,
 given the datatype:
 \bprog
index 57bce2f..28ced22 100644 (file)
@@ -1,5 +1,5 @@
 %
-% $Header: /home/cvs/root/haskell-report/report/exps.verb,v 1.12 2001/11/01 13:43:43 simonpj Exp $
+% $Header: /home/cvs/root/haskell-report/report/exps.verb,v 1.13 2001/11/02 16:26:48 simonpj Exp $
 %
 %*section 3
 %**<title>The Haskell 98 Report: Expressions</title>
@@ -607,54 +607,9 @@ are class methods in the class @Enum@ as defined in the Prelude
 }
 
 The semantics of arithmetic sequences therefore depends entirely
-on the instance declaration for the type "t".  We give here the
-semantics for @Prelude@ types, and indications of the expected semantics
-for other, user-defined, types.
-
-For the types @Int@ and @Integer@, arithmetic sequences have the following
-meaning:
-\begin{itemize}
-\item The sequence "@[@e_1@..]@" is the list "@[@e_1@,@e_1+1@,@e_1+2@,@...@]@".
-
-\item The sequence "@[@e_1@,@e_2@..]@" is the list "@[@e_1@,@e_1+i@,@e_1+2i@,@...@]@",
-where the increment, "i", is "e_2-e_1".  The increment may be zero or negative.
-If the increment is zero, all the list elements are the same.
-
-\item The sequence "@[@e_1@..@e_3@]@" is the list "@[@e_1@,@e_1+1@,@e_1+2@,@...e_3@]@".
-The list is empty if "e_1 > e_3".
-
-\item The sequence "@[@e_1@,@e_2@..@e_3@]@" 
-is the list "@[@e_1@,@e_1+i@,@e_1+2i@,@...e_3@]@",
-where the increment, "i", is "e_2-e_1".  If the increment 
-is positive or zero, the list terminates when the next element would
-be greater than "e_3"; the list is empty if "e_1 > e_3".
-If the increment is negative, the list terminates when the next element would
-be less than "e_3"; the list is empty if "e1 < e_3".
-\end{itemize}
-For other {\em discrete} @Prelude@ types "t" that 
-are instances of @Enum@, namely @()@, @Bool@, @Char@ and @Ordering@,
-the semantics is given by mapping the "e_i" to @Int@ using @fromEnum@,
-using the above rules, and then mapping back to "t" with @toEnum@.
-
-Where the type is also an instance of class @Bounded@ 
-and "e_3" is omitted, an implied "e_3" is added
-of @maxBound@ (if the increment is positive) or @minBound@ (resp. negative).
-For example, @['a'..'z']@ denotes
-the list of lowercase letters in alphabetical order, and @[LT..]@ is the
-list @[LT,EQ,GT]@.
-
-For {\em continuous} @Prelude@ types that are instances of @Enum@,
-namely @Float@ and @Double@, the semantics is given by the rules for @Int@,
-except that the list terminates when the elements become greater than
-"e_3+i/2" for positive increment "i", or when they become less than 
-"e_3+i/2" for negative "i".
-
-See Figure~\ref{standard-classes}%
-%*ignore
-, page~\pageref{standard-classes}
-%*endignore
- and Section~\ref{derived-decls} for more details of which @Prelude@
-type are in @Enum@.
+on the instance declaration for the type "t".  
+Section~\ref{enum-class} for more details of which @Prelude@
+type are in @Enum@ and their semantics.
 
 
 \subsection{List Comprehensions}
index 30a03da..1ea52cd 100644 (file)
@@ -1,5 +1,5 @@
 %
-% $Header: /home/cvs/root/haskell-report/report/preface-13.verb,v 1.10 2001/11/01 13:43:43 simonpj Exp $
+% $Header: /home/cvs/root/haskell-report/report/preface-13.verb,v 1.11 2001/11/02 16:26:48 simonpj Exp $
 %
 %**<title>The Haskell 98 Report: Preface</title>
 %*section
@@ -147,8 +147,8 @@ and, like type signatures, bind to an entity rather than to its name.
 Version~1.4 of the report made the following relatively minor changes to the
 language:
 \begin{itemize}
-\item The character set has been changed to Unicode\index{Unicode
-character set}.
+\item The character set has been changed to 
+Unicode\index{Unicode character set}.
 \item List comprehensions have been generalized to arbitrary
 monads.\index{list comprehension}
 \item Import and export of class methods and constructors is no longer
@@ -298,7 +298,7 @@ Sandra Loosemore,
 Pablo Lopez,
 Olaf Lubeck, 
 Ian Lynagh,
-Christian Maeder
+Christian Maeder,
 Ketil Malde,
 Simon Marlow,
 Michael Marte,
index ed8c50f..26383b8 100644 (file)
@@ -1,8 +1,8 @@
 %
-% $Header: /home/cvs/root/haskell-report/report/syntax-lexical.verb,v 1.5 2001/09/11 16:19:17 simonpj Exp $
+% $Header: /home/cvs/root/haskell-report/report/syntax-lexical.verb,v 1.6 2001/11/02 16:26:48 simonpj Exp $
 % 
 
-@@@
+@@@ 
 
 program                -> \{ lexeme | whitespace \}
 lexeme          -> qvarid | qconid | qop | literal | special | reservedop | reservedid
@@ -49,7 +49,7 @@ uniDigit        -> \tr{any Unicode decimal digit}
 octit   -> @0@ | @1@ | ... | @7@
 hexit   -> digit | @A@ | ... | @F@ | @a@ | ... | @f@
 
-@@@
+@@@ 
 
 \indexsyn{program}%
 \indexsyn{lexeme}%