--------------------------------
authorSimon Peyton Jones <simonpj@microsoft.com>
Mon, 2 Dec 2002 14:53:33 +0000 (14:53 +0000)
committerSimon Peyton Jones <simonpj@microsoft.com>
Mon, 2 Dec 2002 14:53:33 +0000 (14:53 +0000)
This version should typeset the
Haskell 98 language and libraries
as a single book rather than as
two separate reports.
--------------------------------

67 files changed:
libraries/Makefile
report/Makefile
report/array.verb [new file with mode: 0644]
report/basic.verb
report/char.verb [new file with mode: 0644]
report/complex.verb [new file with mode: 0644]
report/cputime.verb [new file with mode: 0644]
report/decls.verb
report/derived.verb
report/directory.verb [new file with mode: 0644]
report/exps.verb
report/h98-revised.html [new file with mode: 0644]
report/haskell.verb
report/haskell98-bugs.html [moved from haskell98-bugs.html with 100% similarity]
report/html.config
report/index.html
report/intro.verb
report/io.verb [new file with mode: 0644]
report/ix.verb [new file with mode: 0644]
report/lexemes.verb
report/lib-code/Array.hs [new file with mode: 0644]
report/lib-code/Char.hs [new file with mode: 0644]
report/lib-code/Complex.hs [new file with mode: 0644]
report/lib-code/IO.hs [new file with mode: 0644]
report/lib-code/Ix.hs [new file with mode: 0644]
report/lib-code/List.hs [new file with mode: 0644]
report/lib-code/Locale.hs [new file with mode: 0644]
report/lib-code/Maybe.hs [new file with mode: 0644]
report/lib-code/Monad.hs [new file with mode: 0644]
report/lib-code/Numeric.hs [new file with mode: 0644]
report/lib-code/Random.hs [new file with mode: 0644]
report/lib-code/Ratio.hs [new file with mode: 0644]
report/lib-code/Time.hs [new file with mode: 0644]
report/lib-hdrs/Array.hs [new file with mode: 0644]
report/lib-hdrs/CPUTime.hs [new file with mode: 0644]
report/lib-hdrs/Char.hs [new file with mode: 0644]
report/lib-hdrs/Complex.hs [new file with mode: 0644]
report/lib-hdrs/Directory.hs [new file with mode: 0644]
report/lib-hdrs/IO.hs [new file with mode: 0644]
report/lib-hdrs/IO1.hs [new file with mode: 0644]
report/lib-hdrs/Ix.hs [new file with mode: 0644]
report/lib-hdrs/List.hs [new file with mode: 0644]
report/lib-hdrs/List1.hs [new file with mode: 0644]
report/lib-hdrs/Locale.hs [new file with mode: 0644]
report/lib-hdrs/Maybe.hs [new file with mode: 0644]
report/lib-hdrs/Monad.hs [new file with mode: 0644]
report/lib-hdrs/Numeric.hs [new file with mode: 0644]
report/lib-hdrs/Random.hs [new file with mode: 0644]
report/lib-hdrs/Ratio.hs [new file with mode: 0644]
report/lib-hdrs/System.hs [new file with mode: 0644]
report/lib-hdrs/Time.hs [new file with mode: 0644]
report/lib-hdrs/Time1.hs [new file with mode: 0644]
report/list.verb [new file with mode: 0644]
report/literate.verb
report/locale.verb [new file with mode: 0644]
report/maybe.verb [new file with mode: 0644]
report/modules.verb
report/monad.verb [new file with mode: 0644]
report/numeric.verb [new file with mode: 0644]
report/pragmas.verb
report/preface-jfp.verb
report/random.verb [new file with mode: 0644]
report/ratio.verb [new file with mode: 0644]
report/standard-prelude.verb
report/syntax-iso.verb
report/system.verb [new file with mode: 0644]
report/time.verb [new file with mode: 0644]

index cbd8335..73ac8bc 100644 (file)
@@ -69,7 +69,7 @@ HEADERS =     headers/Ratio.tex headers/Complex.tex headers/Ix.tex \
                 headers/Maybe.tex headers/IO1.tex headers/Random.tex \
                headers/Time.tex headers/Time1.tex headers/CPUTime.tex \
                headers/Locale.tex 
-
 HEADERSV =     headers/Ratio.verb headers/Complex.verb headers/Ix.verb \
                 headers/Numeric.verb \
                 headers/Array.verb headers/IO.verb headers/Char.verb \
index 2455ab9..6c18521 100644 (file)
@@ -49,10 +49,32 @@ PARTS_NO_PREFACE = iso-chars.tex \
                decls.tex  modules.tex  basic.tex  io-13.tex \
                derived.tex \
                index-extra.tex index-intro.tex layout.tex \
-               literate.tex pragmas.tex standard-prelude.tex
+               literate.tex pragmas.tex standard-prelude.tex \
+               ratio.tex complex.tex ix.tex \
+                numeric.tex \
+                array.tex io.tex char.tex monad.tex list.tex \
+                system.tex directory.tex \
+                maybe.tex time.tex cputime.tex random.tex \
+               locale.tex 
+
 SYNTAX =       syntax-lexical.tex syntax-iso.tex
-PRELUDE =      Prelude.tex PreludeList.tex \
-               PreludeText.tex PreludeIO.tex
+
+CODE =         lib-code/Ratio.tex lib-code/Complex.tex lib-code/Ix.tex \
+                lib-code/Numeric.tex \
+                lib-code/Array.tex lib-code/Char.tex lib-code/List.tex \
+                lib-code/Monad.tex lib-code/Maybe.tex lib-code/IO.tex \
+               lib-code/Time.tex lib-code/Locale.tex
+
+HEADERS =      lib-hdrs/Ratio.tex lib-hdrs/Complex.tex lib-hdrs/Ix.tex \
+                lib-hdrs/Numeric.tex \
+                lib-hdrs/Array.tex lib-hdrs/IO.tex lib-hdrs/Char.tex \
+               lib-hdrs/List.tex lib-hdrs/List1.tex \
+                lib-hdrs/Monad.tex lib-hdrs/System.tex lib-hdrs/Directory.tex \
+                lib-hdrs/Maybe.tex lib-hdrs/IO1.tex lib-hdrs/Random.tex \
+               lib-hdrs/Time.tex lib-hdrs/Time1.tex lib-hdrs/CPUTime.tex \
+               lib-hdrs/Locale.tex 
+
+PRELUDE =      Prelude.tex PreludeList.tex PreludeText.tex PreludeIO.tex
 
 LIBPARTS =     lib-array.tex lib-intro.tex lib-io.tex lib-num.tex lib-os.tex lib-text.tex \
                lib-index-intro.tex lib-posix.tex
@@ -76,17 +98,6 @@ haskell.tex: haskell.verb
 
 haskell.dvi:  haskell.tex ${PARTS} $(SYNTAX) ${PRELUDE}
 
-# Report as formatted for SIGPLAN -- 2 sided, 2-up, odd pages on left.
-# This is a bit horrible.  But almost nobody should need to do this. KH
-sigplan_haskell.dvi: sigplan_haskell.verb sigplan_article.sty \
-                    haskell.tex haskell.ind \
-                    ${PARTS} $(SYNTAX) ${PRELUDE}
-       cp sigplan_article.sty article.sty
-       cp sigplan_haskell.verb haskell.verb
-       -make haskell.dvi
-       cp plain_haskell.verb haskell.verb
-
-
 # I have no idea why run_tex is run twice.  SLPJ
 html: index.html ${PARTS} ${SYNTAX} ${PRELUDE}
        -mkdir haskell98-report-html
@@ -95,16 +106,33 @@ html: index.html ${PARTS} ${SYNTAX} ${PRELUDE}
        $(RUN_INDEX)
        cp index.html *.gif haskell98-report-html
 
-haskell.dvi: haskell.tex haskell.ind ${PARTS} $(SYNTAX) ${PRELUDE}
-
-haskell-libraries.dvi:  haskell-libraries.tex haskell-libraries.ind ${LIBPARTS} ${LIBS}
+haskell.dvi: haskell.tex haskell.ind ${PARTS} $(SYNTAX) ${PRELUDE}  ${CODE} ${HEADERS}
 
-sigplan_haskell-libraries.dvi:  sigplan_haskell-libraries.tex haskell-libraries.ind ${LIBPARTS} ${LIBS}
 
 # remove this rule if you don't have "makeindex"
 haskell.ind: haskell.idx
        $(MAKEINDEX) -i -t haskell.ilg < haskell.idx > haskell.ind
 
+haskell.ps : haskell.dvi
+       dvips haskell.dvi -o haskell.ps
+
+release: haskell.ps html
+       ps2pdf haskell.ps
+       gzip < haskell.ps > $(RELEASE_DIR)/haskell.ps.gz
+       cp haskell.pdf $(RELEASE_DIR)/haskell.pdf.gz
+       cp -r haskell98-report-html $(RELEASE_DIR)
+       tar cvf - haskell98-report-html | gzip > $(RELEASE_DIR)/haskell98-report-html.tar.gz
+       cp h98-revised.html $(RELEASE_DIR)/index.html
+       cp haskell98-bugs.html h98.gif $(RELEASE_DIR)
+
+publish-pdf: report.pdf
+       gzip < report.pdf > y:Haskell/haskell98-report/report.pdf.gz
+
+
+#########################################
+#      Generic stuff
+#########################################
+
 veryclean: clean
        $(RM) *~ 
 
@@ -115,6 +143,63 @@ clean:
        echo "Don't delete the Prelude*.tex files"
        echo "Not everyone has \"perl\" to re-make them"
 
+
+#########################################
+#      Suffix rules
+#########################################
+
+.SUFFIXES:     .hi .hs .verb .tex .dvi
+
+.verb.tex:
+       $(EXPAND) < $< | $(VERBATIM) | ../tools/subsection >$@
+# The 'subsection' part changes section -> chapter for the book style
+
+.hs.verb:
+       $(EXPAND) < $< | $(SPLITPGM) >$@
+
+%.tex: %.hs
+       $(EXPAND) < $< | $(SPLITPGM) | $(VERBATIM) >$@
+
+.hi.tex:
+       $(EXPAND) < $< | $(SPLITPGM) | $(VERBATIM) >$@
+
+.tex.dvi:
+       $(LATEX) $<
+
+
+# -----------------------------------------------------------
+#                      Out of date stuff
+# -----------------------------------------------------------
+
+# Report as formatted for SIGPLAN -- 2 sided, 2-up, odd pages on left.
+# This is a bit horrible.  But almost nobody should need to do this. KH
+sigplan_haskell.dvi: sigplan_haskell.verb sigplan_article.sty \
+                    haskell.tex haskell.ind \
+                    ${PARTS} $(SYNTAX) ${PRELUDE}
+       cp sigplan_article.sty article.sty
+       cp sigplan_haskell.verb haskell.verb
+       -make haskell.dvi
+       cp plain_haskell.verb haskell.verb
+
+
+sigplan_haskell-libraries.dvi:  sigplan_haskell-libraries.tex haskell-libraries.ind ${LIBPARTS} ${LIBS}
+
+haskell-libraries.dvi:  haskell-libraries.tex haskell-libraries.ind ${LIBPARTS} ${LIBS}
+
+# ----------------------- END OF OLD SIGPLAN STUFF -----------------------------------
+
+jfp: h98-book.tex preface-jfp.tex ${PARTS_NO_PREFACE} $(SYNTAX) ${PRELUDE}
+       -mkdir $(JFP_DIR)
+       for n in h98-book.tex preface-jfp.tex \
+               ${PARTS_NO_PREFACE} $(SYNTAX) ${PRELUDE} ; do  \
+               ../tools/subsection < $$n >  $(JFP_DIR)/$$n ; done 
+       cp classes.eps $(JFP_DIR)
+       cp  haskell.bbl $(JFP_DIR)/h98-book.bbl
+       cp Makefile-jfp-book $(JFP_DIR)/Makefile
+
+
+
+
 # Stuff to make the "two-up" version for SIGPLAN Notices:
 # We take the A4 pages and double them up onto (virtual) A3 pages:
 # (two A5 pages make one A4 page; two A4 pages make one A3 page; ...)
@@ -156,44 +241,3 @@ haskell-libraries-2up.dvi : haskell-librariesx.dvi
 haskell-librariesx.dvi : sigplan_haskell-libraries.dvi
        dviselect =4: sigplan_haskell-libraries.dvi haskell-librariesx.dvi
 
-haskell.ps : haskell.dvi
-       dvips haskell.dvi -o haskell.ps
-
-release: haskell.ps html
-       gzip < haskell.ps > $(RELEASE_DIR)/haskell.ps.gz
-       cp -r haskell98-report-html $(RELEASE_DIR)
-       tar cvf - haskell98-report-html | gzip > $(RELEASE_DIR)/haskell98-report-html.tar.gz
-
-publish-pdf: report.pdf
-       gzip < report.pdf > y:Haskell/haskell98-report/report.pdf.gz
-
-jfp: h98-book.tex preface-jfp.tex ${PARTS_NO_PREFACE} $(SYNTAX) ${PRELUDE}
-       -mkdir $(JFP_DIR)
-       for n in h98-book.tex preface-jfp.tex \
-               ${PARTS_NO_PREFACE} $(SYNTAX) ${PRELUDE} ; do  \
-               ../tools/subsection < $$n >  $(JFP_DIR)/$$n ; done 
-       cp classes.eps $(JFP_DIR)
-       cp  haskell.bbl $(JFP_DIR)/h98-book.bbl
-       cp Makefile-jfp-book $(JFP_DIR)/Makefile
-
-#########################################
-#      Suffix rules
-#########################################
-
-.SUFFIXES:     .hi .hs .verb .tex .dvi
-
-.verb.tex:
-       $(EXPAND) < $< | $(VERBATIM) >$@
-
-.hs.verb:
-       $(EXPAND) < $< | $(SPLITPGM) >$@
-
-%.tex: %.hs
-       $(EXPAND) < $< | $(SPLITPGM) | $(VERBATIM) >$@
-
-.hi.tex:
-       $(EXPAND) < $< | $(SPLITPGM) | $(VERBATIM) >$@
-
-.tex.dvi:
-       $(LATEX) $<
-
diff --git a/report/array.verb b/report/array.verb
new file mode 100644 (file)
index 0000000..724d695
--- /dev/null
@@ -0,0 +1,183 @@
+%**<title>The Haskell 98 Library Report: Arrays</title>
+%**~header
+\section{Arrays}
+\label{arrays}
+\index{array}
+
+\outline{
+\inputHS{lib-hdrs/Array}
+}
+
+\Haskell{} provides indexable {\em arrays}, which may be thought of as
+functions whose domains are isomorphic to contiguous subsets of the
+integers.
+Functions restricted in this way can be
+implemented efficiently; in particular, a programmer may
+reasonably expect rapid access to the components.  To ensure
+the possibility of such an implementation, arrays are treated as data, not as
+general functions.
+
+Since most array functions involve the class @Ix@, this module is
+exported from @Array@ so that modules need not import both @Array@ and
+@Ix@. 
+
+\subsection{Array Construction}
+If @a@ is an index type and @b@ is any type, the type of arrays with
+indices in @a@ and elements in @b@ is written @Array a b@.\indextycon{Array}
+An array may be created by the function @array@\indextt{array}.
+The first argument of @array@ is a pair of {\em bounds}, each of the
+index type of the array.  These bounds are the lowest and
+highest indices in the array, in that order.  For example, a
+one-origin vector of length @10@ has bounds @(1,10)@, and a one-origin @10@
+by @10@ matrix has bounds @((1,1),(10,10))@.
+
+The second argument of @array@ is a list of {\em associations}
+of the form ($index$,~$value$).  Typically, this list will
+be expressed as a comprehension.  An association @(i, x)@ defines the
+value of the array at index @i@ to be @x@.  The array is undefined (i.e.~$\bot$) if
+any index in the list is out of bounds.  If any two associations in the
+list have the same index, the value at that index is undefined (i.e.~$\bot$).
+Because the indices must be checked for these errors, @array@ is
+strict in the bounds argument and in the indices of the association list,
+but nonstrict in the values.  Thus, recurrences such as the following are
+possible:
+\bprog
+@
+a = array (1,100) ((1,1) : [(i, i * a!(i-1)) | i <- [2..100]])
+@
+\eprog
+Not every index within the bounds of the array need
+appear in the association list, but the values associated with indices
+that do not appear will be undefined (i.e.~$\bot$).
+Figure~\ref{array-examples} shows some examples that use the
+@array@ constructor.
+
+\begin{figure}[tb]
+\outline{\small
+@
+-- Scaling an array of numbers by a given number:
+scale :: (Num a, Ix b) => a -> Array b a -> Array b a
+scale x a = array b [(i, a!i * x) | i <- range b]
+           where b = bounds a
+
+-- Inverting an array that holds a permutation of its indices
+invPerm :: (Ix a) => Array a a -> Array a a
+invPerm a = array b [(a!i, i) | i <- range b]
+           where b = bounds a
+
+-- The inner product of two vectors
+inner :: (Ix a, Num b) => Array a b -> Array a b -> b
+inner v w = if b == bounds w
+               then sum [v!i * w!i | i <- range b]
+               else error "inconformable arrays for inner product"
+           where b = bounds v
+@
+}
+\ecaption{Array examples}
+\label{array-examples}
+\end{figure}
+
+The @(!)@\index{!@@{\tt {\char'041}}} operator denotes array subscripting.
+% array subscripting -- if the index lies outside the bounds of the
+% array, the result is undefined.  
+The @bounds@\indextt{bounds} function
+applied to an array returns its bounds.
+The functions @indices@\indextt{indices}, @elems@\indextt{elems}, and
+@assocs@,\indextt{assocs} when applied to an array, return lists of
+the indices, elements, or associations, respectively, in index order.
+An array may be constructed from a pair of bounds and a list
+of values in index order using the function @listArray@\indextt{listArray}.
+
+If, in any dimension, the lower bound is greater than the upper bound,
+then the array is legal, but empty.  Indexing an empty array always
+gives an array-bounds error, but @bounds@ still yields the bounds
+with which the array was constructed.
+
+\subsubsection{Accumulated Arrays}
+\index{array!accumulated}
+
+Another array creation function, @accumArray@,\indextt{accumArray}
+relaxes the restriction that a given index may appear at most once in
+the association list, using an {\em accumulating function} which
+combines the values of associations with the same index.
+% \cite{nikhil:id-nouveau,wadler:array-primitive}:
+The first argument of @accumArray@ is the accumulating function; the
+second is an initial value; the remaining two arguments are a bounds
+pair and an association list, as for the @array@ function.
+For example, given a list of values of some index type, @hist@
+produces a histogram of the number of occurrences of each index within
+a specified range:
+\bprog
+@
+hist :: (Ix a, Num b) => (a,a) -> [a] -> Array a b
+hist bnds is = accumArray (+) 0 bnds [(i, 1) | i<-is, inRange bnds i]
+@
+\eprog
+If the accumulating function is strict, then @accumArray@ is
+strict in the values, as well as the indices, in the
+association list.  Thus, unlike ordinary arrays,
+accumulated arrays should not in general be recursive.
+
+\subsection{Incremental Array Updates}
+\label{array-update}
+
+The operator @(//)@\indextt{//} takes an array and a list of pairs and returns
+an array identical to the left argument except that it has
+been updated by the associations in the right argument.  (As with
+the @array@ function, the indices in the association list must
+be unique for the updated elements to be defined.)  For example,
+if @m@ is a 1-origin, @n@ by @n@ matrix, then
+@m//[((i,i), 0) | i <- [1..n]]@ is the same matrix, except with
+the diagonal zeroed.
+
+@accum@\indextt{accum} "f" takes an array
+and an association list and accumulates pairs from the list into
+the array with the accumulating function "f".  Thus @accumArray@
+can be defined using @accum@:\nopagebreak[4]
+\bprog
+@
+accumArray f z b = accum f (array b [(i, z) | i <- range b])
+@
+\eprogNoSkip
+
+\subsection{Derived Arrays}
+\index{array!derived}
+
+The two functions @fmap@\indextt{fmap} and @ixmap@\indextt{ixmap}
+derive new arrays from existing ones; they may be
+thought of as providing function composition on the left and right,
+respectively, with the mapping that the original array embodies.
+The @fmap@ function transforms the array values while 
+@ixmap@ allows for transformations on array indices.
+Figure~\ref{derived-array-examples} shows some examples.
+
+\begin{figure}[tb]
+\outline{\small
+@
+-- A rectangular subarray
+subArray :: (Ix a) => (a,a) -> Array a b -> Array a b
+subArray bnds = ixmap bnds (\i->i)
+
+-- A row of a matrix
+row :: (Ix a, Ix b) => a -> Array (a,b) c -> Array b c
+row i x = ixmap (l',u') (\j->(i,j)) x where ((_,l'),(_,u')) = bounds x
+
+-- Diagonal of a matrix (assumed to be square)
+diag :: (Ix a) => Array (a,a) b -> Array a b
+diag x = ixmap (l,u) (\i->(i,i)) x
+       where 
+         ((l,_),(u,_)) = bounds x
+
+-- Projection of first components of an array of pairs
+firstArray :: (Ix a) => Array a (b,c) -> Array a b
+firstArray = fmap (\(x,y)->x)
+@
+}
+\ecaption{Derived array examples}
+\label{derived-array-examples}
+\end{figure}
+
+\subsection{Library {\tt Array}}
+\label {Libarray}
+\inputHS{lib-code/Array}
+%**~footer
index 319e56b..e422700 100644 (file)
@@ -1,5 +1,5 @@
 %
-% $Header: /home/cvs/root/haskell-report/report/basic.verb,v 1.12 2002/12/02 11:22:01 simonpj Exp $
+% $Header: /home/cvs/root/haskell-report/report/basic.verb,v 1.13 2002/12/02 14:53:27 simonpj Exp $
 %
 %**<title>The Haskell 98 Report: Basic Types and Classes</title>
 %*section 6
@@ -182,6 +182,7 @@ Report contains many more.
 \indextycon{IOError}
 
 \subsubsection{Other Types}
+{\small
 \bprog
 @
 data  Maybe a     =  Nothing | Just a  deriving (Eq, Ord, Read, Show)
@@ -202,6 +203,7 @@ data  Ordering    =  LT | EQ | GT deriving
 \indextt{maybe}
 \indextt{either}
 \eprog
+}
 The @Maybe@ type is an instance of classes @Functor@, @Monad@,
 and @MonadPlus@.  The @Ordering@ type is used by @compare@
 in the class @Ord@. The functions @maybe@ and @either@ are found in
diff --git a/report/char.verb b/report/char.verb
new file mode 100644 (file)
index 0000000..c9ec32b
--- /dev/null
@@ -0,0 +1,98 @@
+%**<title>The Haskell 98 Library Report: Character Utilities</title>
+%**~header
+\section{Character Utilities}
+
+\outline{
+\inputHS{lib-hdrs/Char}
+}
+\indextt{isAscii}
+\indextt{isLatin1}
+\indextt{isControl}
+\indextt{isPrint}
+\indextt{isSpace}
+\indextt{isUpper}
+\indextt{isLower}
+\indextt{isAlpha}
+\indextt{isDigit}
+\indextt{isOctDigit}
+\indextt{isHexDigit}
+\indextt{isAlphaNum}
+\indextt{toUpper}
+\indextt{toLower}
+
+This library provides a limited set of operations on the Unicode
+character set.  
+The first 128 entries of this character set are identical to the
+ASCII set; with the next 128 entries comes the remainder of the
+Latin-1 character set.
+This module offers only a limited view of the
+full Unicode character set; the full set of Unicode character
+attributes is not accessible in this library.
+
+Unicode characters may be divided into five general categories:
+non-printing, lower case alphabetic, other alphabetic, numeric digits, and
+other printable characters.  For the purposes of Haskell, any
+alphabetic character which is not lower case is treated as upper case
+(Unicode actually has three cases: upper, lower, and title).  Numeric
+digits may be part of identifiers but digits outside the ASCII range are not
+used by the reader to represent numbers.  
+
+For each sort of Unicode character, here are the predicates which
+return @True@:
+\begin{center}
+\begin{tabular}{|l|llll|}
+\hline
+Character Type & Predicates  & & & \\
+\hline
+Lower Case Alphabetic & @isPrint@ & @isAlphaNum@ & @isAlpha@ & @isLower@ \\
+Other Alphabetic & @isPrint@ & @isAlphaNum@ & @isAlpha@ & @isUpper@ \\
+Digits & @isPrint@ & @isAlphaNum@ & & \\
+Other Printable & @isPrint@ & & & \\
+Non-printing & & & &\\
+\hline
+\end{tabular}
+\end{center}
+
+The @isDigit@, @isOctDigit@, and @isHexDigit@ functions select only
+ASCII characters.  @intToDigit@ and @digitToInt@ convert between 
+a single digit @Char@ and the corresponding @Int@.  
+@digitToInt@ operates fails unless its argument satisfies @isHexDigit@,
+but recognises both upper and lower-case hexadecimal digits (i.e. @'0'@..@'9'@,
+@'a'@..@'f'@, @'A'@..@'F'@).  @intToDigit@ fails unless its argument is in the range
+@0@..@15@, and generates lower-case hexadecimal digits.
+
+The @isSpace@ function recognizes only white characters in the Latin-1
+range.
+
+The function @showLitChar@ converts a character to a string using
+only printable characters, using Haskell source-language escape conventions.
+The function @lexLitChar@ does the reverse, returning the sequence of characters 
+that encode the character.
+The function @readLitChar@ does the same, but in addition converts the 
+to the character that it encodes.  For example:
+\bprog
+@
+  showLitChar '\n' s       =  "\\n" ++ s
+  lexLitChar  "\\nHello"   =  [("\\n", "Hello")]
+  readLitChar "\\nHello"   =  [('\n', "Hello")]
+@
+\eprog
+
+Function @toUpper@ converts a letter to the corresponding
+upper-case letter, leaving any other character unchanged.  Any
+Unicode letter which has an upper-case equivalent is transformed.
+Similarly, @toLower@ converts a letter to the
+corresponding lower-case letter, leaving any other character
+unchanged.
+
+The @ord@ and @chr@ functions are @fromEnum@ and @toEnum@
+restricted to the type @Char@.
+
+\clearpage
+\subsection{Library {\tt Char}}
+\label{Char}
+\inputHS{lib-code/Char}
+
+%**~footer
+
+
diff --git a/report/complex.verb b/report/complex.verb
new file mode 100644 (file)
index 0000000..1ffe6aa
--- /dev/null
@@ -0,0 +1,49 @@
+%**<title>The Haskell 98 Library Report: Complex Numbers</title>
+%**~header
+\section{Complex Numbers}
+\label{lib-num}
+
+\outline{
+\inputHS{lib-hdrs/Complex}
+}
+
+Complex numbers are an algebraic type.
+The constructor @(:+)@\indextt{:+} forms a complex number from its
+real and imaginary rectangular components.  This constructor is
+strict: if either the real part or the imaginary part of the number is
+$\bot$, the entire number is $\bot$.  A complex number may also
+be formed from polar components of magnitude and phase by the function
+@mkPolar@\indextt{mkPolar}.  The function @cis@\indextt{polar}
+produces a complex number from an angle "t".
+Put another way, @cis@ "t" is a complex value with magnitude "1"
+and phase "t" (modulo "2\pi").
+
+The function @polar@\indextt{polar} takes a complex number and
+returns a (magnitude, phase) pair in canonical form: The magnitude is
+nonnegative, and the phase, in the range $(- \pi , \pi ]$; if the
+magnitude is zero, then so is the phase.  
+
+The functions @realPart@\indextt{realPart} and
+@imagPart@\indextt{imagPart} extract the rectangular components of a
+complex number and the functions @magnitude@\indextt{magnitude} and
+@phase@\indextt{phase} extract the polar components of a complex
+number.  The function @conjugate@\indextt{conjugate} computes the
+conjugate of a complex number in the usual way.
+
+The magnitude and sign of a complex number are defined as follows:
+\bprog
+@
+abs z            =  magnitude z :+ 0
+signum 0         =  0
+signum z@@(x:+y)   =  x/r :+ y/r  where r = magnitude z
+@
+\eprog
+That is, @abs@ $z$ is a number with the magnitude of $z$, but oriented
+in the positive real direction, whereas @signum@ $z$ has the phase of
+$z$, but unit magnitude.
+
+\subsection{Library {\tt Complex}}
+\inputHS{lib-code/Complex}
+
+%**~footer
+
diff --git a/report/cputime.verb b/report/cputime.verb
new file mode 100644 (file)
index 0000000..c45ef4b
--- /dev/null
@@ -0,0 +1,19 @@
+%**<title>The Haskell 98 Library Report: CPU Time</title>
+%**~header
+\section{CPU Time}
+\label{cputime}
+\index{CPU time}
+\index{execution time}
+
+\outline {
+\inputHS{lib-hdrs/CPUTime}
+}
+
+Computation @getCPUTime@ returns the number of picoseconds of CPU time
+used by the current program.  The precision of this result is given by
+@cpuTimePrecision@.  This is the smallest measurable difference in CPU
+time that the implementation can record, and is given as an integral
+number of picoseconds.
+
+%**~footer
+
index a6919c6..bd3ccc7 100644 (file)
@@ -1,5 +1,5 @@
 %
-% $Header: /home/cvs/root/haskell-report/report/decls.verb,v 1.15 2002/12/02 11:22:01 simonpj Exp $
+% $Header: /home/cvs/root/haskell-report/report/decls.verb,v 1.16 2002/12/02 14:53:27 simonpj Exp $
 %
 %**<title>The Haskell 98 Report: Declarations</title>
 %*section 4
@@ -112,6 +112,8 @@ class methods}---instantiated on the named type.
 For example, suppose we wish to overload the operations @(+)@ and
 @negate@ on types @Int@ and @Float@.  We introduce a new
 type class called @Num@:\nopagebreak[4]
+\par
+{\small
 \bprog
 @
   class Num a  where          -- simplified class declaration for Num
@@ -119,6 +121,7 @@ type class called @Num@:\nopagebreak[4]
     negate :: a -> a
 @
 \eprog
+}
 This declaration may be read ``a type @a@ is an instance of the class
 @Num@ if there are class methods @(+)@ and @negate@, of the
 given types, defined on it.''
index 2e1a112..5555c8e 100644 (file)
@@ -1,5 +1,5 @@
 %
-% $Header: /home/cvs/root/haskell-report/report/derived.verb,v 1.9 2002/12/02 11:22:01 simonpj Exp $
+% $Header: /home/cvs/root/haskell-report/report/derived.verb,v 1.10 2002/12/02 14:53:27 simonpj Exp $
 %
 % The paragraph describing the formats of standard representations might
 % be deleted, since the info is already in the Prelude.  
@@ -8,7 +8,6 @@
 % isn't quite Haskell.  
 
 %**<title>The Haskell 98 Report: Derived Instances</title>
-%*section D
 %**~header
 
 \section{Specification of Derived Instances}
@@ -180,6 +179,8 @@ 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 
+\par
+{\small
 \bprog
 @
   enumFrom x           = enumFromTo x lastCon
@@ -191,6 +192,7 @@ The definitions of the remaining methods are
   enumFromThenTo x y z = map toEnum [fromEnum x, fromEnum y .. fromEnum z]
 @
 \eprog
+}
 where @firstCon@ and @lastCon@ are respectively the first and last
 constructors listed in the @data@ declaration.
 For example,
@@ -473,7 +475,7 @@ the class declaration shown in Figure~\ref{standard-classes}
 (page~\pageref{standard-classes}).
 
 \begin{figure}[tb]
-\outlinec{
+\outlinec{\small
 @
 infixr 5 :^:
 data Tree a =  Leaf a  |  Tree a :^: Tree a
diff --git a/report/directory.verb b/report/directory.verb
new file mode 100644 (file)
index 0000000..f4acda3
--- /dev/null
@@ -0,0 +1,165 @@
+%**<title>The Haskell 98 Library Report: Directory functions</title>
+%**~header
+
+%% Other useful functions from SML 96 include modification time
+%% and path-testing (is this a full path/real path).
+
+\section{Directory Functions}
+\index{directories}
+\index{the file system}
+
+\outline{
+\inputHS{lib-hdrs/Directory}
+}
+\indextt{createDirectory}\indextt{removeDirectory}\indextt{removeFile}
+\indextt{renameDirectory}\indextt{renameFile}
+\indextt{getDirectoryContents}\indextt{getCurrentDirectory}
+\indextt{setCurrentDirectory}
+
+These functions operate on directories in the file system.  
+
+Any @Directory@ operation could raise an @isIllegalOperation@, as
+described in Section~\ref{IOError}; all other permissible errors are
+described below.  Note that, in particular, if an implementation does
+not support an operation it should raise an @isIllegalOperation@.
+A directory contains a series of entries, each of which is a named
+reference to a file system object (file, directory etc.).  Some
+entries may be hidden, inaccessible, or have some administrative
+function (for instance, ``.'' or ``..'' under POSIX), but all such
+entries are considered to form part of the directory contents.
+Entries in sub-directories are not, however, considered to form part
+of the directory contents.  Although there may be
+file system objects other than files and directories, this library
+does not distinguish between physical files and other non-directory
+objects.  All such objects should therefore be treated as if they are files.
+
+Each file system object is referenced by a {\it path}\index{path}.  There is
+normally at least one absolute path to each file system object.  In
+some operating systems, it may also be possible to have paths which
+are relative to the current directory.
+
+Computation @createDirectory@~"dir" creates a new directory "dir" which is
+initially empty, or as near to empty as the operating system allows.
+\index{making directories}
+
+{\em Error~reporting}.
+The @createDirectory@ computation may fail with:
+@isPermissionError@ if the user is not permitted to create the directory;
+@isAlreadyExistsError@ if the directory already exists; or @isDoesNotExistError@ if
+the new directory's parent does not exist.
+
+Computation @removeDirectory@~"dir" removes an existing directory
+"dir"\index{deleting directories}\index{removing directories}.  The
+implementation may specify additional constraints which must be
+satisfied before a directory can be removed (for instance, the directory has to
+be empty, or may not be in use by other processes).  It is not legal
+for an implementation to partially remove a directory unless the
+entire directory is removed. A conformant implementation need not
+support directory removal in all situations (for instance, removal of the root
+directory).
+
+Computation @removeFile@~"file" removes the directory entry for an existing
+file "file", where "file" is not itself a directory\index{deleting
+files}\index{removing files}. The implementation may specify additional
+constraints which must be satisfied before a file can be removed (for instance, the
+file may not be in use by other processes).
+
+{\em Error~reporting}.
+The @removeDirectory@ and @removeFile@ computations may fail with:
+@isPermissionError@ if the user is not permitted to remove the file/directory;
+or @isDoesNotExistError@ if the file/directory does not exist.
+
+Computation @renameDirectory@~"old"~"new" changes the name of an existing
+directory from "old" to "new"\index{renaming directories}\index{moving
+directories}.  If the "new" directory already exists, it is atomically
+replaced by the "old" directory.  If the "new" directory is neither
+the "old" directory nor an alias of the "old" directory, it is removed
+as if by @removeDirectory@.  A conformant implementation need not
+support renaming directories in all situations (for instance, renaming to an
+existing directory, or across different physical devices), but the
+constraints must be documented.
+
+Computation @renameFile@~"old"~"new" changes the name of an existing file
+system object from "old" to "new"\index{renaming files}\index{moving files}.
+If the "new" object already exists, it is atomically replaced by the "old"
+object.  Neither path may refer to an existing directory.  A conformant
+implementation need not support renaming files in all situations
+(for instance, renaming across different physical devices), but the constraints must be
+documented.
+
+{\em Error~reporting}.
+The @renameDirectory@ and @renameFile@ computations may fail with:
+@isPermissionError@ if the user is not permitted to rename the file/directory,
+or if either argument to @renameFile@ is a directory;
+or @isDoesNotExistError@ if the file/directory does not exist.
+
+Computation @getDirectoryContents@~"dir" returns a list of {\em all} entries
+in "dir"\index{reading a directory}.
+Each entry in the returned list is named relative to the directory "dir", not as an absolute path.
+
+If the operating system has a notion of current directories,
+@getCurrentDirectory@ returns an absolute path to the
+current directory of the calling process\index{current directory}.
+
+{\em Error~reporting}.
+The @getDirectoryContents@ and @getCurrentDirectory@ computations may fail with:
+@isPermissionError@ if the user is not permitted to access the directory;
+or @isDoesNotExistError@ if the directory does not exist.
+
+If the operating system has a notion of current directories,
+@setCurrentDirectory@~"dir" changes the current directory of the
+calling process to "dir"\index{changing the directory}\index{setting the directory}.
+
+{\em Error~reporting}.
+@setCurrentDirectory@ may fail with:
+@isPermissionError@ if the user is not permitted to change directory
+to that specified;
+or @isDoesNotExistError@ if the directory does not exist.
+
+The @Permissions@ type is used to record whether certain operations are
+permissible on a file/directory.  @getPermissions@ and
+@setPermissions@ get and set these permissions, respectively.  
+Permissions apply both to files and directories.  For
+directories, the @executable@ field will be @False@, and for files the
+@searchable@ field will be @False@.  Note that directories may be
+searchable without being readable, if permission has been given to use
+them as part of a path, but not to examine the directory contents.
+
+Note that to change
+some, but not all permissions, a construct on the following lines must
+be used.  
+\bprog
+@
+makeReadable f = do
+                   p <- getPermissions f
+                   setPermissions f (p {readable = True})
+@
+\eprog
+The operation @doesDirectoryExist@ returns @True@ if the argument file
+exists and is a directory, and @False@ otherwise. The operation @doesFileExist@ returns @True@
+if the argument file exists and is not a directory, and @False@ otherwise.
+
+The @getModificationTime@ operation returns the
+clock time at which the file/directory was last modified.
+
+{\em Error~reporting}.
+@get(set)Permissions@,
+@doesFile(Directory)Exist@,
+and @getModificationTime@
+may fail with:
+@isPermissionError@ if the user is not permitted to access
+the appropriate information;
+or @isDoesNotExistError@ if the file/directory does not exist.
+The @setPermissions@
+computation may also fail with:
+@isPermissionError@ if the user is not permitted to change
+the permission for the specified file or directory;
+or @isDoesNotExistError@ if the file/directory does not exist.
+% Duplicates the first case above, and would require
+% extensive consistency checking throughout. KH
+% The @doesFileExist@ and @doesDirectoryExist@ computations
+% may also fail with @isPermissionError@ if some part of the path
+% to the file/directory cannot be searched.
+
+%**~footer
+
index 7a38bd4..4934fc0 100644 (file)
@@ -1,5 +1,5 @@
 %
-% $Header: /home/cvs/root/haskell-report/report/exps.verb,v 1.16 2002/12/02 11:22:01 simonpj Exp $
+% $Header: /home/cvs/root/haskell-report/report/exps.verb,v 1.17 2002/12/02 14:53:27 simonpj Exp $
 %
 %*section 3
 %**<title>The Haskell 98 Report: Expressions</title>
@@ -342,7 +342,7 @@ it may legally be written as @\(x:xs)->x@.
 The set of patterns must be {\em linear}\index{linearity}%
 \index{linear pattern}---no variable may appear more than once in the set.
 
-\outline{
+\outline{\small
 \paragraph*{Translation:}
 The following identity holds:
 \begin{center}
@@ -773,7 +773,7 @@ let (x,y) = undefined in @"e"@
 \eprog
 does not cause an execution-time error until @x@ or @y@ is evaluated.
 
-\outline{
+\outline{\small
 \paragraph*{Translation:} The dynamic semantics of the expression 
 "@let {@ d_1 @;@ ...  @;@ d_n @} in@ e_0" are captured by this
 translation: After removing all type signatures, each
@@ -1507,7 +1507,7 @@ not expected that it will use them directly, since that
 would generate rather inefficient code.
   
 \begin{figure}[tb]
-\outlinec{
+\outlinec{\small
 \begin{tabular}{@@{}cl}
 (a)&@case @$e$@ of { @$alts$@ } @$=$@ (\@$v$@ -> case @$v$@ of { @$alts$@ }) @"e"\\
 &{\rm where $v$ is a new variable}\\
@@ -1546,7 +1546,7 @@ $x_1$@ })@ $\ldots$ @(case @$v$@ of { @$p$@ -> @$x_n$@})@\\
 \end{figure}
 
 \begin{figure}[tb]
-\outlinec{
+\outlinec{\small
 \begin{tabular}{@@{}cl}
 (g)&@case @$v$@ of { @$K\ p_1 \ldots p_n$@ -> @$e$@; _ -> @$e'$@ }@\\
 &$=$@ case @$v$@ of {@\\
diff --git a/report/h98-revised.html b/report/h98-revised.html
new file mode 100644 (file)
index 0000000..3c72918
--- /dev/null
@@ -0,0 +1,53 @@
+<html>
+<head>
+</head>
+<HEAD>
+<TITLE>Haskell 98: The Revised Report</title></head>
+</head>
+</head>
+</head>
+</head>
+</HEAD>
+<BODY>
+<div align=center>
+<img src="h98.gif" alt="Haskell 98">
+</div>
+
+<h1>Haskell 98: The Revised Report (Dec 2002)</h1>
+
+The Haskell 98 Report has undergone an extensive process of revision since its publication 
+in January 1999.  This process converged in December 2002, producing the Revised Report.
+<p>
+The Revised Report is published by Cambridge University Press, as a book 
+<a href="http://titles.cambridge.org/catalogue.asp?isbn=0521826144">"Haskell 98 language
+and libraries: the Revised Report"</a>, and also as a Special Issue of the Journal of Functional
+Programming 13(1) Jan 2003.
+<p>
+The text and sources of the Report are neverthless still available online, as follows:
+<ul>
+<p><li> The Haskell 98 Report (revised) 
+<ul>
+<li> <a href="haskell98-report-html/index.html">HTML</a>
+<li> <a href="haskell.ps.gz">Gzipped Postscript</a>
+<li> <a href="haskell.pdf">PDF</a>
+</ul>
+<p>
+<li> <a href="haskell98-report-html.tar.gz">Gzipped tar bundle of the HTML sources</a> for local browsing.
+
+
+<p><li>
+<a href="haskell98-bugs.html">A complete list of all changes</a> made to both reports between the Jan 1999 publication
+and the Revised Report.
+
+<p>
+<li> The sources for both Reports are in a 
+<a href="http://cvs.haskell.org/cgi-bin/cvsweb.cgi/haskell-report/">
+publicly visible CVS repository</a>.
+</ul>
+
+
+<hr>
+<address>Simon Peyton Jones, simonpj@microsoft.com</address>
+</body>
+</html>
+
index a3d7dfd..a97b47e 100644 (file)
@@ -1,43 +1,13 @@
-%
-% $Header: /home/cvs/root/haskell-report/report/haskell.verb,v 1.13 2002/12/02 11:22:01 simonpj Exp $
-%
-
-% NOTE:--------------------------------------------------------------
-% The formatting of this report and the ``new font selection scheme''
-% for LaTeX don't agree w/ each other.  Using an ``oldlfont'' style
-% option may help.
-% -------------------------------------------------------------------
-%
-
-% -------------------------------------------------------------------
-% formatting for ONE-SIDED printing:
-%  * De-comment the \documentstyle, etc., here; comment out the
-%    two-sided ones below.
-%  * Change the definition of \startnewstuff (below).
-%  * Copy the pre-built index file for one-sided printing:
-%      cp haskell.ind.one-sided haskell.ind
-%  * Comment out the "twosidefix" stuff from Joe Fasel, just below.
-%  * If you don't have "makeindex", make the adjustments
-%    listed in the README file.
-%  * Run "make haskell.dvi" several times (three, at most) to be
-%    sure that cross-references stabilise.  [For the 1.1 report,
-%    one run should be enough.]
-%\documentstyle[11pt,makeidx]{article}
-%\oddsidemargin=.25in
-%\evensidemargin=.25in
-
-% formatting for double-sided
-\documentclass[titlepage,twoside,11pt]{article}
+% Formatting for double-sided
+\documentclass[twoside,11pt]{book}
 
+\usepackage{times}
 \usepackage{makeidx}
 \usepackage{graphicx}
 
 \evensidemargin=0in
 \oddsidemargin=.5in
-
-% Inverted for SIGPLAN -- Page 1 is a LEFT page!!
-%\evensidemargin=.5in
-%\oddsidemargin=0in
+\sloppy
 
 %---------------------------------------------------------------------
 % Joe Fasel said this "twosidefix" is necessary if you really
@@ -52,9 +22,6 @@
 \makeatother
 %---------------------------------------------------------------------
 
-\sloppy
-
-
 % the major sections have \cleardoublepages between them
 % if you want those between EVERY section, change the
 % following defn:
@@ -73,7 +40,8 @@
 \renewcommand{\bottomfraction}{1.0}
 
 % table of contents: show only down to subsections
-\setcounter{tocdepth}{2}
+\setcounter{tocdepth}{3}
+\setcounter{secnumdepth}{3}
 
 % general formatting
 \textheight=8.5in
@@ -99,7 +67,8 @@
 \newcommand{\bi}{\begin{itemize}}
 \newcommand{\ei}{\end{itemize}}
 \newcommand{\struthack}[1]{\rule{0pt}{#1}}
-\newcommand{\inputHS}{\input}
+\newcommand{\inputHS}[1]{{\small \input{#1}}}
+% Use smaller font 
 
 \newcommand{\ToDo}[1]{}
 %\newcommand{\ToDo}[1]{({\bf $\spadesuit$ ToDo:} {\em #1})}
 \newcommand{\indexdi}[1]{\index{#1@@{\tt #1} (class)!derived instance}}
 \newcommand{\indexnote}[1]{#1n}
 \newcommand{\emptystr}{[\,]}
+\newcommand{\ignorehtml}[1]{#1}
 
 \makeatletter
 \def\theindex{\@@restonecoltrue\if@@twocolumn\@@restonecolfalse\fi
 
 % outlined figures
 \newcommand{\ecaption}[1]{\vspace{-1 ex}\caption{#1}\vspace{1 ex}}
-% partain fiddled here...
-%   also had to change two lines in verbatim.lex from
-%<SYNTAX>{nl}"|"{sp}   { printf ("$\\\\ \n$\\it "); 
-%                        printf ("$\\>\\makebox[3em]{$|$}$\\it "); }
-% to
-%
-%<SYNTAX>{nl}"|"{sp}   { printf ("$\\\\ \n$\\it "); 
-%                        printf ("$\\>\\makebox[3.5em]{$|$}$\\it "); }
-% so things would still line up.  Oh what a hack.
-%
-%\newcommand{\outline}{\outlinewidth{1.0}}
-%\newcommand{\outlinewidth}[2]{
-%\begin{center}
-%\fbox{ \begin{minipage}{#1\textwidth}
-%\vspace{1 ex}
-%#2
-%\end{minipage} }
-%\vspace{1 ex}
-%\end{center}
-%}
-% 6.0in (\textwidth) - 15pt (overfullness) ~=~ 415pt
 \newcommand{\outline}[1]{%
 \begin{center}
 \fbox{ \begin{minipage}{415pt}
 
 \newcommand{\outlinec}{\outline}  % Centered outlines in html
 
-% haskell code
-% partain fiddled here...
-% \newcommand{\bprog}{\par \begin{tabular}{|l} 
-%                   \mbox \bgroup \begin{minipage} {\textwidth} }
-% 6.0in (\textwidth) - 17pt (\parindent) ~=~ 412pt
-%\newcommand{\bprog}{\par \begin{tabular}{@@{}l@@{}} 
-%                   \mbox \bgroup \begin{minipage} {412pt} }
-%\newcommand{\eprog}{\end{minipage} 
-%                    \egroup
-%                    \end{tabular}\\[\parskip]}
-% 17pt is \parindent
-% this method gives a 17pt indent in _all_ situations
 \newcommand{\bprog}{%
 \par\noindent\begin{tabular}{@@{\hspace*{17pt}}l@@{}}}
 \newcommand{\eprog}{%
 \end{tabular}\\[\parskip]}
 \newcommand{\eprogNoSkip}{%
 \end{tabular}}
+
 %
 % variants for stdprelude; don't indent, and skip a little more
 \newcommand{\bprogB}{%
 \newcommand{\unbindvar}[2]{\ti{unbindvar}\ \db{#1}\ #2}
 \newcommand{\unbindcon}[2]{\ti{unbindcon}\ \db{#1}\ #2}
 
-%
-% \newcommand{\bindnone}{\ab{[], []}}
-% \newcommand{\bindvar}[2]{\ab{[\,#1 \mapsto #2\,], []}}
-% \newcommand{\bindcon}[2]{\ab{[], [\,#1 \mapsto #2\,]}}
-% \newcommand{\bindconlarge}[4]{
-%  \langle [], [\,#1 \mapsto \langle \pile{#2 \\ #3 \rangle\,] #4 \rangle}}
-% \newcommand{\bindmod}[2]{[\,#1 \mapsto #2\,]}
-%
 % Haskell syntax macros: math mode assumed
 \newcommand{\system}[2]{#1@;;@\cdots@;;@#2}
 \newcommand{\module}[4]{module\ #1@:@\ #2\ #3\ #4}
-%%% \newcommand{\exportnone}{\,}
-%%% \newcommand{\export}[1]{@export@\ #1@;@}
-%%% \newcommand{\importnone}{\,}
-%%% \newcommand{\importcomb}[2]{#1\ #2}
-%%% \newcommand{\import}[1]{@import@\ #1@;@}
-%%% \newcommand{\importwith}[2]{@import@\ #1\ #2@;@}
-%%% \newcommand{\rename}[2]{#1@<-@#2}
-%%% \newcommand{\declcomb}[2]{#1\ @;;@\ #2}
 \newcommand{\exposing}[1]{@expose@\ #1}
 \newcommand{\hiding}[1]{@hide@\ #1}
 \newcommand{\importnone}{\;}
 \newcommand{\signature}[2]{#1\ @::@\ #2}
 \newcommand{\binding}[2]{#1\ @=@\ #2}
 \newcommand{\lamexpr}[2]{@\@ #1 @->@ #2}
+
 % While lambda defs. change...  if change, take care of preceding line MMG
 \newcommand{\lamb}{@\ @}
 \newcommand{\whereexpr}[2]{#1\ @where@\ @{@\ #2\ @}@}
 \newcommand{\prefix}[1]{\tr{prefix}\ #1}
 %
 \newcommand{\tl}[1]{{\sc #1}}
-%OLD: \newcommand{\Haskell}{{\sc Haskell}}
 \newcommand{\Haskell}{Haskell}
 
-%\newcommand{\subsubsubsection}[1]{\par\noindent{\it #1}}
 \newcommand{\subsubsubsection}{\subsubsection*}
+\newcommand{\subsubsubsubsection}{\subsubsubsection*}
 
 %\sloppy
 
 
 \setcounter{page}{0}
 
+% ------------------------- Title page -----------------------------------
+
 \begin{titlepage}
 
 \setcounter{page}{0}
 \outline{
 \vspace{.3in}
 \begin{center}
-{\LARGE\bf Report on the} \\[.1in]
-{\LARGE\bf Programming Language} \\[.3in]
-{\huge\bf Haskell 98} \\[.3in]
-{\Large\bf A Non-strict, Purely Functional Language} \\[.3in]
-{\large\bf Revised: Sept 2002}
+{\LARGE\bf Haskell 98 Language and Libraries} \\[.1in]
+{\LARGE\bf The Revised Report} \\[.3in]
 \end{center}
+\vspace{.3in}
+}
 \vspace{.15in}
 \begin{center} \large
-\begin{tabular}{l@@{\hspace{5mm}}l}
-Simon Peyton Jones$^8$ [editor] & John Hughes$^3$ [editor] \\
-Lennart Augustsson$^3$         & Dave Barton$^7$ \\
-Brian Boutel$^4$               & Warren Burton$^5$ \\
-Joseph Fasel$^6$               & Kevin Hammond$^2$ \\
-Ralf Hinze$^{12}$              & Paul Hudak$^1$ \\
-Thomas Johnsson$^3$            & Mark Jones$^9$ \\
-John Launchbury$^{14}$                 & Erik Meijer$^{10}$ \\
-John Peterson$^1$              & Alastair Reid$^1$ \\
-Colin Runciman$^{13}$          & Philip Wadler$^{11}$
-\end{tabular}
+Simon Peyton Jones (editor)
 \end{center}
 \vspace{.15in}
 
-\begin{quotation} \noindent
-Authors' affiliations:
-(1)~Yale University
-(2)~University of St.~Andrews
-(3)~Chalmers University of Technology
-(4)~Victoria University of Wellington
-(5)~Simon Fraser University
-(6)~Los Alamos National Laboratory
-(7)~Intermetrics
-(8)~Microsoft Research, Cambridge
-(9)~University of Nottingham
-(10)~Utrecht University
-(11)~Bell Labs
-(12)~University of Bonn
-(13)~York University
-(14)~Oregon Graduate Institute
-\end{quotation}
-\vspace{.2in}
+\vspace{3in}
 
-\begin{center}
-Copyright (c) Simon Peyton Jones and John Hughes. 
-\end{center}
-{\em The authors intend this Report to belong to the entire Haskell
-community, and so we grant permission to copy and distribute it for
-any purpose, provided that it is reproduced in its entirety,
-including this Notice. Modified versions of this Report may also be
-copied and distributed for any purpose, provided that the modified
-version is clearly presented as such, and that it does not claim to be
-a definition of the language Haskell 98.}
-}
-
-% \outline{
-% \vspace{.3in}
-% \begin{center}
-% {\LARGE\bf Report on the} \\[.1in]
-% {\LARGE\bf Programming Language} \\[.3in]
-% {\huge\bf Haskell} \\[.3in]
-% {\Large\bf A Non-strict, Purely Functional Language} \\[.3in]
-% {\Large\bf Version 1.3} \\[.1in]
-% {\large\bf 1st June 1995}
-% \end{center}
-% \vspace{.15in}
-% \begin{center} \large
-% Kevin Hammond$^1$ [editor] \\
-% Lennart Augustsson$^2$ \\
-% Brian Boutel$^3$ \\
-% Warren Burton$^4$ \\
-% Joseph Fasel$^5$ \\
-% Andy Gordon$^6$ \\
-% Mark Jones$^7$ \\
-% John Peterson$^8$  \\
-% Simon Peyton Jones$^1$ \\
-% \end{center}
-% \vspace{.15in}
-% 
-% \begin{quotation} \noindent
-% Authors' affiliations:
-% (1)~University of Glasgow,
-% (2)~Chalmers University of Technology,
-% (3)~Victoria University of Wellington,
-% (4)~Simon Fraser University,
-% (5)~Los Alamos National Laboratory,
-% (6)~Cambridge University,
-% (7)~Nottingham University,
-% (8)~Yale University.
-% \end{quotation}
-% \vspace{.2in}
-% }
+\begin{center} \emph{Copyright notice.} \end{center}
 
+The authors and publisher intend this Report to belong to the entire Haskell
+community, and grants permission to copy and distribute it for any
+purpose, provided that it is reproduced in its
+entirety, including this Notice. Modified versions of this Report may
+also be copied and distributed for any 
+purpose,
+provided that the modified version is clearly presented as such, and
+that it does not claim to be a definition of the language Haskell 98.
 \end{titlepage}
 
+% ------------------------- Preface -----------------------------------
+
 \pagenumbering{roman}
 
 \clearpage
@@ -525,44 +383,56 @@ a definition of the language Haskell 98.}
 \parskip=10pt plus2pt minus2pt
 \setlength{\parindent}{0cm}
 
-%\input{preface-10}
-%\startnewstuff
-%\input{preface-11}
-%\startnewstuff
-%\input{preface-12}
-%\startnewstuff
-%\pagestyle{myheadings}
-\input{preface-13}
-%\markboth{\rm \thepage\hfil \sl \leftmark}{{\sl \rightmark}\hfil \rm\thepage}
+\input{preface-jfp}
+
+% ------------------------- Part I: language report -----------------------------------
+
 \pagestyle{headings}
 \startnewstuff
 \pagenumbering{arabic}
 
+\part{The Haskell 98 Language}
+
 \input{intro}\startnewsection
 \input{lexemes}\startnewsection
 \input{exps}\startnewsection
 \input{decls}\startnewsection
 \input{modules}\startnewsection
 \input{basic}\startnewsection
-%%\input{io}%
-%\setcounter{section}{6}
-\input{io-13}%
-%%
-%%\startnewstuff
-\startnewsection
-\appendix
+\input{io-13}\startnewsection
+
+% \appendix
 \input{standard-prelude}\startnewsection
-%\input{libraries}\startnewsection
 \input{syntax-iso}\startnewsection
-
-% Literate stuff included in syntax-iso now
-% \input{literate}\startnewsection
-%% \input{short_semantics}\startnewsection
-%%\input{iosemant}\startnewsection
-%%\input{iooptions}\startnewsection
 \input{derived}\startnewsection
 \input{pragmas}
 %%
+
+% ------------------------- Part II: libraries report -----------------------------------
+
+\part{The Haskell 98 Libraries}
+
+\input{ratio}\startnewsection
+\input{complex}\startnewsection
+\input{numeric}\startnewsection
+\input{ix}\startnewsection
+\input{array}\startnewsection
+\input{list}\startnewsection
+\input{maybe}\startnewsection
+\input{char}\startnewsection
+\input{monad}\startnewsection
+\input{io}\startnewsection
+\input{directory}\startnewsection
+\input{system}\startnewsection
+\input{time}\startnewsection
+\input{locale}\startnewsection
+\input{cputime}\startnewsection
+\input{random}\startnewsection
+
+
+
+% ------------------------- Index and references -----------------------------------
+
 \startnewstuff
 % insert the extra indexing things LAST
 \input{index-extra}
@@ -574,6 +444,7 @@ a definition of the language Haskell 98.}
 %
 \startnewstuff
 \printindex
+
 \end{document}
 
 % Local Variables: 
index 19d02dc..92d12ef 100644 (file)
@@ -1,7 +1,7 @@
 aux=haskell.aux
 htmldir=haskell98-report-html/
 refs=reportrefs
-files= preface-13.verb
+files= preface-jfp.verb
 files= intro.verb
 files= lexemes.verb
 files= exps.verb
@@ -14,6 +14,24 @@ files=syntax-iso.verb
 files=literate.verb
 files=derived.verb
 files=pragmas.verb
+
+files=ratio.verb
+files=complex.verb
+files=numeric.verb
+files=ix.verb
+files=array.verb
+files=list.verb
+files=maybe.verb
+files=char.verb
+files=monad.verb
+files=io.verb
+files=directory.verb
+files=system.verb
+files=time.verb
+files=locale.verb
+files=cputime.verb
+files=random.verb
+
 files=haskell.bbl
 
 index=haskell98-report-html/index98.html
@@ -26,11 +44,11 @@ style=article
 ~nxt=<a href="~next.html">next</a>
 ~funct=<a href="prelude-index.html">function index</a>
 ~contents=<a href="index98.html">contents</a>
-~foot=<br><font size=2>Sept 2002</font>
+~foot=<br><font size=2>December 2002</font>
 ~footer=<hr>~id~top | ~back | ~nxt | ~contents | ~funct ~foot
 ~sfooter=<hr>~id~top | back | ~nxt | ~contents | ~funct ~foot
 ~efooter=<hr>~id~top | ~back | next | ~contents | ~funct ~foot
 ~header=~style ~id ~top | ~back | ~nxt | ~contents | ~funct <br><hr>
 ~sheader=~style ~id ~top | back | ~nxt | ~contents | ~funct <br><hr>
 ~eheader=~style ~id ~top | ~back | next | ~contents | ~funct <br><hr>
-~indexHeader=<title>Haskell 98 Index</title>~style ~id~top | ~funct <br><h3>Haskell 98 Report: Index</h3>
+~indexHeader=<title>Haskell 98 Contents</title>~style ~id~top | ~funct <br><h3>Haskell 98 Report: Contentsx</h3>
index 6b5dd21..33fc480 100644 (file)
@@ -4,27 +4,53 @@
 <div align=center>
 <img src="h98.gif" alt="Haskell 98">
 
-<h3>Haskell 98: A Non-strict, Purely Functional Language</h3>
-<h3 align="center">Revised: Sept 2002</h3>
+<h1>Haskell 98 language and libraries: The Revised Report</h1>
+<h3 align="center">December 2002</h3>
 </div>
 <hr>
-<h3>Brief Table of Contents</h3>
+<h2>Brief Table of Contents</h2>
 <ul>
 <li><a href="index98.html">Full Table of Contents</a>
-<li><a href="preface-13.html">Preface</a>
+<li><a href="preface-jfp.html">Preface</a>
 
-<li><a href="intro.html">Introduction</a>
-<li><a href="lexemes.html">Lexical Structure</a>
-<li><a href="exps.html">Expressions</a>
-<li><a href="decls.html">Declarations and Bindings</a>
-<li><a href="modules.html">Modules</a>
-<li><a href="basic.html">Basic Types</a>
-<li><a href="io-13.html">Input/Output</a>
-<li><a href="standard-prelude.html">Standard Prelude</a>
-<li><a href="syntax-iso.html">Syntax</a>
-<li><a href="literate.html">Literate Comments</a>
-<li><a href="derived.html">Derived Instances</a>
-<li><a href="pragmas.html">Pragmas</a>
+<p>
+<h3>Part I: Language</h3>
+<p>
+<li><a href="intro.html">1. Introduction</a> 
+<li><a href="lexemes.html">2. Lexical Structure</a>
+<li><a href="exps.html">3. Expressions</a>
+<li><a href="decls.html">4. Declarations and Bindings</a>
+<li><a href="modules.html">5. Modules</a>
+<li><a href="basic.html">6. Basic Types</a>
+<li><a href="io-13.html">7. Input/Output</a>
+<li><a href="standard-prelude.html">8. Standard Prelude</a>
+<li><a href="syntax-iso.html">9. Syntax</a>
+<li><a href="derived.html">10. Derived Instances</a>
+<li><a href="pragmas.html">11. Pragmas</a>
+
+<p>
+<h2>Part II: Libraries</h2>
+<p>
+
+<li><a href="ratio.html">12. Ratio</a>
+<li><a href="complex.html">13. Complex</a>
+<li><a href="numeric.html">14. Numeric</a>
+<li><a href="ix.html">15. Ix</a>
+<li><a href="array.html">16. Array</a>
+<li><a href="list.html">17. List</a>
+<li><a href="maybe.html">18. Maybe</a>
+<li><a href="char.html">19. Char</a>
+<li><a href="monad.html">20. Monad</a>
+<li><a href="io.html">21. IO</a>
+<li><a href="directory.html">22. Directory</a>
+<li><a href="system.html">23. System</a>
+<li><a href="time.html">24. Time</a>
+<li><a href="locale.html">25. Locale</a>
+<li><a href="cputime.html">26. CPUTime</a>
+<li><a href="random.html">27. Random</a>
+
+<p>
+<p>
 
 <li><a href="haskell.html">Bibliography</a>
 <li><a href="prelude-index.html">Index of Prelude Functions and Types</a>
index 7799b0a..45c36d9 100644 (file)
@@ -1,5 +1,5 @@
 %
-% $Header: /home/cvs/root/haskell-report/report/intro.verb,v 1.4 2002/12/02 11:22:01 simonpj Exp $
+% $Header: /home/cvs/root/haskell-report/report/intro.verb,v 1.5 2002/12/02 14:53:29 simonpj Exp $
 %
 %**<title>The Haskell 98 Report: Introduction</title>
 %*section 1
@@ -166,7 +166,7 @@ will probably try to provide useful information about
 errors.  See Section~\ref{basic-errors}.
 
 
-
+ <
 \subsection{Namespaces}
 \index{namespaces}
 \label{namespaces}
diff --git a/report/io.verb b/report/io.verb
new file mode 100644 (file)
index 0000000..ef0c24b
--- /dev/null
@@ -0,0 +1,637 @@
+%**<title>The Haskell 98 Library Report: IO</title>
+%**~header
+\section{Input/Output}
+\label{IO}
+\index{input/output}
+\index{I/O}
+\indextt{IO}
+
+% Gotta break the figure ...
+\outline{
+\inputHS{lib-hdrs/IO}
+}
+\outline{
+\inputHS{lib-hdrs/IO1}
+}
+
+The monadic I/O system used in \Haskell{} is described by the
+\Haskell{} language report.  Commonly used I/O functions such as
+@print@ are part of the standard prelude and need not be explicitly
+imported.  This library contain more advanced I/O features.
+Some related operations on file systems are contained in the
+@Directory@ library.
+
+\subsection{I/O Errors}
+\index{I/O errors}
+\label{IOError}
+Errors of type @IOError@ are used by the I/O monad.  This is an
+abstract type; the library provides functions to interrogate and
+construct values in @IOError@:\indextt{IOError}
+\begin{itemize}
+\item
+@isAlreadyExistsError@\indextt{isAlreadyExistsError}
+ -- the operation failed because one of its
+arguments already exists.
+\item
+@isDoesNotExistError@\indextt{isDoesNotExistError}
+ -- the operation failed because one of its
+arguments does not exist.
+\item
+@isAlreadyInUseError@\indextt{isAlreadyInUseError}
+ -- the operation failed because one of its
+arguments is a single-use resource, which is already being used (for
+example, opening the same file twice for writing might give this
+error).
+\item
+@isFullError@\indextt{isFullError}
+ -- the operation failed because the device is full.
+\item
+@isEOFError@\indextt{isEOFError}
+ -- the operation failed because the end of file
+has been reached.
+\item
+@isIllegalOperation@\indextt{isIllegalOperation}
+ -- the operation is not possible.
+\item
+@isPermissionError@\indextt{isPermissionError}
+ -- the operation failed because the user does not
+have sufficient operating system privilege to perform that operation.
+\item
+@isUserError@\indextt{isUserError}
+ -- a programmer-defined error value has been raised using
+@fail@.\indextt{fail}
+\end{itemize}
+All these functions return a @Bool@, which is @True@ if
+its argument is the corresponding kind of error, and @False@
+otherwise.  
+
+Any computation which returns an @IO@ result may fail with
+@isIllegalOperation@.  Additional errors which could be raised by
+an implementation are listed after the corresponding operation.  In
+some cases, an implementation will not be able to distinguish between
+the possible error causes.  In this case it should return
+@isIllegalOperation@.
+
+Three additional functions are provided to obtain information about an
+error value.  These are @ioeGetHandle@\indextt{ioeGetHandle} which
+returns @Just@~"hdl" if the error value refers to handle "hdl" and
+@Nothing@ otherwise; @ioeGetFileName@\indextt{ioeGetFileName} which
+returns @Just@~"name" if the error value refers to file "name", and
+@Nothing@ otherwise; and @ioeGetErrorString@\indextt{ioeGetErrorString} which returns a
+string.  For ``user'' errors (those which are raised using @fail@),
+the string returned by @ioeGetErrorString@ is the argument that was passed to
+@fail@; for all other errors, the string is implementation-dependent.
+
+The @try@ function returns an error in a computation explicitly using
+the @Either@ type.
+
+The @bracket@ function 
+captures a common allocate, compute, deallocate idiom in which the
+deallocation step must occur even in the case of an error during
+computation.  This is similar to try-catch-finally in Java.
+% Inline the code here since there's no other functions in IO that
+% are not primitive.
+
+
+
+\subsection{Files and Handles}
+\Haskell{} interfaces to the external world through an abstract {\em file
+system}\index{file system}.  This file system is a collection of named {\em file
+system objects}, which may be organised
+in {\em directories}\index{directories} (see @Directory@).  
+In some implementations, directories may themselves be file system
+objects and could be entries in other directories.  For simplicity,
+any non-directory file system object is termed a {\em file}\index{file},
+although it could in fact be a communication channel, or any other
+object recognised by the operating system.  {\em Physical
+files}\index{physical file} are 
+persistent, ordered files, and normally reside on disk.
+
+File and directory names are values of type @String@, whose precise
+meaning is operating system dependent.  Files can be opened, yielding
+a handle which can then be used to operate on the contents of that
+file.
+
+\label{Handles}
+\index{handles}
+
+\Haskell{} defines operations to read and write characters from and to files,
+represented by values of type @Handle@.  Each value of this type is a {\em
+handle}: a record used by the \Haskell{} run-time system to {\em manage} I/O
+with file system objects.  A handle has at least the following properties:
+
+\begin{itemize}
+\item
+ whether it manages input or output or both;
+\item
+ whether it is {\em open}, {\em closed} or {\em semi-closed};
+\item
+ whether the object is seekable;
+\item
+ whether buffering is disabled, or enabled on a line or block basis;
+\item
+ a buffer (whose length may be zero).
+\end{itemize}
+
+Most handles will also have a current I/O position indicating where the next
+input or output operation will occur.  A handle is {\em readable} if it
+manages only input or both input and output; likewise, it is {\em writable} if
+it manages only output or both input and output.  A handle is {\em open} when
+first allocated.  Once it is closed it can no longer be used for either input
+or output, though an implementation cannot re-use its storage while references
+remain to it.  Handles are in the @Show@ and @Eq@ classes.  The string
+produced by showing a handle is system dependent; it should include 
+enough information to identify the handle for debugging.  A handle is
+equal according to @==@ only to itself; no attempt
+is made to compare the internal state of different handles for equality.
+
+\subsubsection{Standard Handles}
+\label{StandardHandles}
+\index{standard handles}
+
+Three handles are allocated during program initialisation.  The first
+two (@stdin@\indextt{stdin} and @stdout@\indextt{stdout}) manage input or output from the \Haskell{}
+program's standard input or output channel respectively.  The third
+(@stderr@\indextt{stderr}) manages output to the standard error channel.  These
+handles are initially open.
+
+\subsubsection{Semi-Closed Handles}
+\label{SemiClosed}
+\index{semi-closed handles}
+
+The operation "@hGetContents@ hdl"\indextt{hGetContents} (Section~\ref{hGetContents})
+puts a handle "hdl" into an intermediate
+state, {\em semi-closed}.  In this state, "hdl" is effectively closed,
+but items are read from "hdl" on demand and accumulated in a special
+list returned by @hGetContents@~"hdl".
+Any operation that fails because a handle is
+closed, also fails if a handle is semi-closed. The only exception is @hClose@.
+A semi-closed handle becomes closed:
+\begin{itemize}
+\item
+if  @hClose@ is applied to it;
+\item
+if an I/O error occurs when reading an item from the handle;
+\item
+or once the entire contents of the handle has been read.
+\end{itemize}
+
+Once a semi-closed handle becomes closed, the contents of the
+associated list becomes fixed.  The contents of this final list is
+only partially specified: it will contain at least all the items of
+the stream that were evaluated prior to the handle becoming closed.
+
+Any I/O errors encountered while a handle is semi-closed are simply
+discarded.
+\subsubsection{File locking}
+
+Implementations should enforce as far as possible, at least locally to the
+\Haskell{} process, multiple-reader single-writer locking on files.
+That is, {\em there may either be many handles on the same file which manage
+input, or just one handle on the file which manages output}.  If any
+open or semi-closed handle is managing a file for output, no new
+handle can be allocated for that file.  If any open or semi-closed
+handle is managing a file for input, new handles can only be allocated
+if they do not manage output.  Whether two files are the same is
+implementation-dependent, but they should normally be the same if they
+have the same absolute path name and neither has been renamed, for
+example.
+
+{\em Warning}: the @readFile@ operation (Section 7.1 of the Haskell Language Report)
+holds a semi-closed handle on the file until the entire contents of the file have been
+consumed.  It follows that an attempt to write to a file (using @writeFile@, for example)
+that was earlier opened by @readFile@ will usually result in 
+failure with @isAlreadyInUseError@.
+\indextt{readFile}
+\indextt{writeFile}
+
+
+\subsection{Opening and Closing Files}
+\label{OpeningClosing}
+
+\subsubsection{Opening Files}
+\label{Opening}
+\index{opening a file}
+\index{creating a file}
+
+Computation @openFile@~"file"~"mode"\indextt{openFile} allocates and
+returns a new, open handle to manage the file "file".
+% I don't believe this footnote is technically correct -- functions
+% are never computations IIRC: the computation is the action
+% that occurs when the function is applied to a state token -- KH
+% \footnote{We use
+% the term "computation" instead of "function" here to separate
+% functions which denote actions in the I/O monad from those outside the monad.}
+It manages
+input if "mode"\indextycon{IOMode} is @ReadMode@\indextt{ReadMode},
+output if "mode" is @WriteMode@\indextt{WriteMode} or
+@AppendMode@,\indextt{AppendMode} and both input and output if mode is
+@ReadWriteMode@.\indextt{ReadWriteMode}
+
+If the file does not exist and it is opened for output, it should be created
+as a new file.  If "mode" is @WriteMode@ and the file already exists, then it
+should be truncated to zero length.  Some operating systems delete empty
+files, so there is no guarantee that the file will exist following an
+@openFile@ with "mode" @WriteMode@ unless it is subsequently written to
+successfully.  The handle is positioned at the end of the file if "mode" is
+@AppendMode@, and otherwise at the beginning (in which case its internal I/O
+position is 0).  The initial buffer mode is implementation-dependent.
+
+If @openFile@ fails on a file opened for output, the file may still
+have been created if it did not already exist.
+
+{\em Error reporting}: the @openFile@ computation may fail with
+@isAlreadyInUseError@ if the file is already open and cannot be
+reopened;
+@isDoesNotExistError@ if the file does not exist; or
+@isPermissionError@ if the user does not have
+permission to open the file.
+\indextt{isAlreadyInUseError}
+\indextt{isDoesNotExistError}
+\indextt{isPermissionError}
+
+\subsubsection{Closing Files}
+\label{Closing}
+\index{closing a file}
+
+Computation @hClose@~"hdl"\indextt{hClose} makes handle "hdl" closed.  Before the
+computation finishes, if "hdl" is writable its buffer is flushed as
+for @hFlush@.
+Performing @hClose@ on a handle that has already been closed has no effect; 
+doing so not an error.  All other operations on a closed handle will fail.
+If @hClose@ fails for any reason, any further operations (apart from @hClose@) on the 
+handle will still fail as if "hdl" had been successfully closed.
+
+\subsection{Determining the Size of a File}
+\label{FileSize}
+\index{size of file}
+
+For a handle "hdl" which is attached to a physical file, @hFileSize@\indextt{hFileSize}
+"hdl" returns the size of that file in 8-bit bytes ("\geq" 0).
+
+\subsubsection{Detecting the End of Input}
+\label{EOF}
+\index{end of file}
+
+For a readable handle "hdl", computation @hIsEOF@~"hdl"\indextt{hIsEOF} returns @True@
+if no further input can be taken from "hdl"; for a handle attached to a 
+physical file this means that the current I/O position is equal to the length of the file.
+Otherwise, it returns @False@.  The computation @isEOF@\indextt{isEOF} is identical,
+except that it works only on @stdin@.
+
+% The computation may fail with:
+% \begin{itemize}
+% \item
+% @HardwareFault@
+% A physical I/O error has occurred.
+% [@EIO@]
+% \item
+% @ResourceExhausted@
+% Insufficient resources are available to perform the operation.
+% [@ENOMEM@]
+% \item
+% @IllegalOperation@
+% The handle is not open for reading.
+% \end{itemize}
+
+\subsubsection{Buffering Operations}
+\label{Buffering}
+\index{file buffering}
+
+Three kinds of buffering are supported: line-buffering, 
+block-buffering or no-buffering.  These modes have the following effects.
+For output, items are written out, or {\em flushed}, from the internal buffer 
+according to the buffer mode:
+\begin{itemize}
+\item
+{\bf line-buffering:}
+the entire buffer is flushed whenever a newline is output, the
+buffer overflows, a @hFlush@ is issued, or the handle is closed.
+\item
+{\bf block-buffering:}
+the entire buffer is written out whenever it overflows, a @hFlush@ is
+issued, or the handle is closed.
+\item
+{\bf no-buffering:}
+output is written immediately, and never stored in the buffer.
+\end{itemize}
+An implementation is free to flush the buffer more frequently, but not 
+less frequently, than
+specified above.  The buffer is emptied as soon as it has been written out.
+
+Similarly, input occurs according to the buffer mode for handle "hdl".
+\begin{itemize}
+\item
+{\bf line-buffering:}
+when the buffer for "hdl" is not empty, the next item is obtained from
+the buffer; otherwise, when the buffer is empty, characters are read into
+the buffer until the next newline character is encountered or the buffer is full.  No
+characters are available until the newline character is available or the buffer is full.
+\item
+{\bf block-buffering:} 
+when the buffer for "hdl" becomes empty, the
+next block of data is read into the buffer.
+\item
+{\bf no-buffering:} 
+the next input item is read and returned.  The @hLookAhead@\indextt{hLookAhead} 
+operation (Section~\ref{hLookAhead}) implies that
+even a no-buffered handle may require a one-character buffer.
+\end{itemize}
+
+For most implementations, physical files will normally be block-buffered 
+and terminals will normally be line-buffered.
+
+Computation @hSetBuffering@~"hdl"~"mode"\indextt{hSetBuffering} sets the
+mode of buffering for handle "hdl" on subsequent reads and writes.
+\begin{itemize}
+\item
+If "mode" is @LineBuffering@, line-buffering is
+enabled if possible.
+\item
+If "mode" is @BlockBuffering@~"size", then block-buffering
+is enabled if possible.  The size of the buffer is "n" items
+if "size" is @Just @"n" and is otherwise implementation-dependent.
+\item
+If "mode" is @NoBuffering@, then buffering is disabled if possible.
+\end{itemize}
+
+If the buffer mode is changed from @BlockBuffering@ or
+@LineBuffering@ to @NoBuffering@, then 
+\begin{itemize}
+\item
+if "hdl" is writable, the buffer is flushed as for 
+@hFlush@;
+\item
+if "hdl" is not writable, the contents of the buffer is discarded.
+\end{itemize}
+
+{\em Error reporting}: the @hSetBuffering@ computation may fail with
+@isPermissionError@ if
+the handle has already been used for reading or writing
+and the implementation does not allow the buffering mode to
+be changed.
+
+Computation @hGetBuffering@~"hdl"\indextt{hGetBuffering} returns the current buffering mode
+for "hdl".
+
+The default buffering mode when a handle is opened is
+implementation-dependent and may depend on the file system object which is
+attached to that handle.
+
+\subsubsection{Flushing Buffers}
+\label{Flushing}
+\index{flushing a file buffer}
+
+Computation @hFlush@~"hdl"\indextt{hFlush} causes any items buffered for output in
+handle "hdl" to be sent immediately to the operating system.
+
+{\em Error reporting}: the @hFlush@ computation may fail with:
+@isFullError@ if the device is full; @isPermissionError@ if a
+system resource limit would be exceeded.  It is unspecified whether the
+characters in the buffer are discarded or retained under these circumstances.
+
+\subsection{Repositioning Handles}
+\label{Seeking}
+\index{random access files}
+\index{seeking a file}
+
+\subsubsection{Revisiting an I/O Position}
+
+Computation @hGetPosn@~"hdl"\indextt{hGetPosn} returns the current I/O position of "hdl" as a
+value of the abstract type @HandlePosn@.  If a call to "@hGetPosn@~h" returns a position "p",
+then computation @hSetPosn@~"p"\indextt{hSetPosn} sets the
+position of "h" to the position it held at the time of the call to @hGetPosn@.
+
+
+{\em Error reporting}: the @hSetPosn@ computation may fail with:
+@isPermissionError@ if a system resource limit would be exceeded.
+
+\subsubsection{Seeking to a new Position}
+
+Computation @hSeek@~"hdl"~"mode"~"i"\indextt{hSeek} sets the position of handle
+"hdl" depending on "mode".\indextycon{SeekMode}  If "mode" is:
+\begin{itemize}
+\item
+@AbsoluteSeek@:\indextt{AbsoluteSeek} the position of "hdl" is set to "i".
+\item
+@RelativeSeek@:\indextt{RelativeSeek} the position of "hdl" is set to offset "i" from
+the current position.
+\item
+@SeekFromEnd@:\indextt{SeekFromEnd} the position of "hdl" is set to offset "i" from
+the end of the file.
+\end{itemize}
+The offset is given in terms of 8-bit bytes.
+
+If "hdl" is block- or line-buffered, then seeking to a position which is not
+in the current buffer will first cause any items in the output buffer to be
+written to the device, and then cause the input buffer to be discarded.  Some
+handles may not be seekable (see @hIsSeekable@), or only support a subset of
+the possible positioning operations (for instance, it may only be possible to
+seek to the end of a tape, or to a positive offset from the beginning or
+current position).  It is not possible to set a negative I/O position, or for
+a physical file, an I/O position beyond the current end-of-file.
+
+{\em Error reporting}:
+the @hSeek@ computation may fail with:
+@isPermissionError@ if a system resource limit would be exceeded.
+
+\subsection{Handle Properties}
+\label{Query}
+
+The functions 
+@hIsOpen@\indextt{hIsOpen}, 
+@hIsClosed@\indextt{hIsClosed},
+@hIsReadable@\indextt{hIsReadable},
+@hIsWritable@\indextt{hIsWritable} and
+@hIsSeekable@\indextt{hIsSeekable}
+return information about the properties of a handle.
+Each of these returns @True@ if the handle has the specified property, and
+@False@ otherwise.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% Haskell 1.3 Text Input: LibReadTextIO
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\subsection{Text Input and Output}
+\index{reading from a file}
+%\indextt{LibReadTextIO}
+
+Here we define a standard set of input operations for reading
+characters and strings from text files, using handles.  Many of these
+functions are generalizations of Prelude functions.  I/O in the
+Prelude generally uses @stdin@ and @stdout@; here, handles are explicitly
+specified by the I/O operation.
+
+\subsubsection{Checking for Input}
+\label{hReady}
+\label{hWaitForInput}
+\index{polling a handle for input}
+
+Computation @hWaitForInput@~"hdl"~"t"\indextt{hWaitForInput} 
+waits until input is available on handle "hdl".
+It returns @True@ as soon as input is available on "hdl", or @False@ if no input is available
+within "t" milliseconds.
+
+Computation @hReady@~"hdl"\indextt{hReady} indicates whether at least one item is
+available for input from handle "hdl".
+
+{\em Error reporting}.
+The @hWaitForInput@ and @hReady@ computations fail with
+@isEOFError@ if the end of file has been reached.
+
+\subsubsection{Reading Input}
+
+Computation @hGetChar@~"hdl"\indextt{hGetChar} reads a character from
+the file or channel managed by "hdl".
+
+Computation @hGetLine@~"hdl"\indextt{hGetLine} reads a line from the file or
+channel managed by "hdl". The Prelude's @getLine@ is a shorthand
+for @hGetLine stdin@.
+{\em Error reporting}.
+The @hGetChar@ computation fails with
+@isEOFError@ if the end of file has been reached.
+The @hGetLine@ fails with @isEOFError@ if the end of file is encountered
+when reading the {\em first} character of the line. If @hGetLine@ encounters
+end-of-file at any other point while reading in a line, it is treated as
+a line terminator and the (partial) line is returned.
+
+
+\subsubsection{Reading Ahead}
+\label{hLookAhead}
+\index{lookahead}
+
+Computation @hLookAhead@~"hdl"\indextt{hLookAhead} returns the next character from handle
+"hdl" without removing it from the input buffer, blocking until a
+character is available.
+
+{\em Error reporting}:
+the @hLookAhead@ computation may fail with:
+@isEOFError@ if the end of file has been reached.
+
+\subsubsection{Reading The Entire Input}
+\label{hGetContents}
+\index{get the contents of a file}
+
+Computation @hGetContents@~"hdl"\indextt{hGetContents} returns the list of
+characters corresponding to the unread portion of the channel or file managed
+by "hdl", which is made semi-closed.
+
+{\em Error reporting}:
+the @hGetContents@ computation may fail with:
+@isEOFError@ if the end of file has been reached.
+
+\subsubsection{Text Output}
+
+Computation @hPutChar@~"hdl"~"c"\indextt{hPutChar} writes the character "c" to the file
+or channel managed by "hdl".  Characters may be buffered if buffering
+is enabled for "hdl".
+
+Computation @hPutStr@~"hdl"~"s"\indextt{hPutStr} writes the string
+"s" to the file or channel managed by "hdl".
+
+Computation @hPrint@~"hdl"~"t"\indextt{hPrint} writes the string representation of "t"
+given by the @shows@ function to the file or channel managed by "hdl" and appends a newline.
+
+{\em Error reporting}:
+the @hPutChar@, @hPutStr@ and @hPrint@ computations may fail with:
+@isFull@-@Error@ if the device is full;
+or @isPermissionError@ if another system resource limit would be exceeded.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% Haskell 1.3 Examples
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\subsection{Examples}
+\index{input/output examples}
+
+Here are some simple examples to illustrate \Haskell{} I/O.
+
+\subsubsection{Summing Two Numbers}
+
+This program reads and sums two @Integer@s.
+\bprog
+@
+import IO
+
+main = do
+         hSetBuffering stdout NoBuffering            
+         putStr   "Enter an integer: "        
+         x1 <- readNum 
+         putStr   "Enter another integer: "          
+         x2 <- readNum                          
+         putStr  ("Their sum is " ++ show (x1+x2) ++ "\n")
+       where readNum :: IO Integer
+               -- Providing a type signature avoids reliance on
+               -- the defaulting rule to fix the type of x1,x2
+             readNum = readLn
+@
+\eprog
+
+\subsubsection{Copying Files}
+
+A simple program to create a copy of a file, with all lower-case
+characters translated to upper-case.  This program will not allow a
+file to be copied to itself.  This version uses character-level I/O.
+Note that exactly two arguments must be supplied to the program.
+\bprog
+@
+import IO
+import System
+import Char( toUpper )
+
+main = do 
+         [f1,f2] <- getArgs
+         h1 <- openFile f1 ReadMode     
+         h2 <- openFile f2 WriteMode 
+         copyFile h1 h2            
+         hClose h1                  
+         hClose h2
+
+copyFile h1 h2 = do
+                   eof <- hIsEOF h1
+                   if eof then return () else
+                      do
+                        c <- hGetChar h1
+                        hPutChar h2 (toUpper c)   
+                        copyFile h1 h2
+@
+\eprog
+
+An equivalent but much shorter version, using string I/O is:
+\bprog
+@
+import System
+import Char( toUpper )
+
+main = do
+         [f1,f2] <- getArgs
+         s <- readFile f1
+         writeFile f2 (map toUpper s)
+@
+\eprog
+
+%      Not any more in Haskell 98!
+% The @~@ used in the patterns above is a necessary consequence of the
+% @do@-notation which has been used for the I/O operations.  In general,
+% if the pattern on the left of any @<-@ fails to match, the value of
+% the entire @do@-expression is defined to be the ``zero'' in the
+% underlying monad.  However, since the @IO@ monad has no zero, the @~@
+% is required in order to force the pattern to be irrefutable.  Without
+% the @~@, a class error would occur because there is no instance of
+% @IO@ for class @MonadZero@.
+
+\subsection{Library @IO@}
+
+\inputHS{lib-code/IO}
+
+%**~footer
diff --git a/report/ix.verb b/report/ix.verb
new file mode 100644 (file)
index 0000000..d921764
--- /dev/null
@@ -0,0 +1,113 @@
+%**<title>The Haskell 98 Library Report: Indexing Operations</title>
+%**~header
+\section{Indexing Operations}
+
+\outline{
+\inputHS{lib-hdrs/Ix}
+}
+The @Ix@ class is used to map a contiguous subrange of values in a
+type onto integers.  It is used primarily for array indexing (see
+Section~\ref{arrays}).  
+The @Ix@ class contains the methods @range@\indextt{range},
+@index@\indextt{index}, and @inRange@\indextt{inRange}. 
+The @index@ operation maps a bounding pair, which defines the lower
+and upper bounds of the range, and a 
+subscript, to an integer.  The @range@ operation enumerates all
+subscripts; the @inRange@ operation tells whether a particular subscript
+lies in the range defined by a bounding pair.
+
+An implementation is entitled to assume the following laws about these
+operations:
+\bprog
+@
+   range (l,u) !! index (l,u) i == i   -- when i is in range
+   inRange (l,u) i             == i `elem` range (l,u)
+   map index (range (l,u))      == [0..rangeSize (l,u)]
+@
+\eprog
+
+% It is the responsibility of the programmer to enforce bounds
+% checking for non-derived instances of class @Ix@, if desired.
+% An implementation is not required to check that an index
+% lies within the bounds of an array when accessing that array.
+
+\subsection{Deriving Instances of @Ix@}
+\index{Ix@@{\tt Ix}!derived instance}
+
+It is possible to derive an instance of @Ix@ automatically, using
+a @deriving@ clause on a @data@ declaration (Section~4.3.3
+of the Language Report).
+Such derived instance declarations for the class @Ix@ are only possible
+for enumerations\index{enumeration} (i.e.~datatypes having
+only nullary constructors) and single-constructor datatypes,
+whose constituent types are instances of @Ix@.   A Haskell implementation
+must provide @Ix@ instances for tuples up to at least size 15.
+
+\begin{itemize}
+\item
+For an {\em enumeration}, the nullary constructors are assumed to be
+numbered left-to-right with the indices being $0$ to $n-1\/$ inclusive.
+This is the same numbering defined by the @Enum@ class.  For example,
+given the datatype:
+\bprog
+@
+data Colour = Red | Orange | Yellow | Green | Blue | Indigo | Violet
+@
+\eprog
+we would have:
+\bprog
+@
+range   (Yellow,Blue)        ==  [Yellow,Green,Blue]
+index   (Yellow,Blue) Green  ==  1
+inRange (Yellow,Blue) Red    ==  False
+@
+\eprog
+\item
+For {\em single-constructor datatypes}, the derived instance declarations
+are as shown for tuples in
+Figure~\ref{prelude-index}.
+\end{itemize}
+
+\begin{figure}[tb]
+\outline{\small
+@
+instance  (Ix a, Ix b)  => Ix (a,b) where
+        range ((l,l'),(u,u'))
+                = [(i,i') | i <- range (l,u), i' <- range (l',u')]
+        index ((l,l'),(u,u')) (i,i')
+                =  index (l,u) i * rangeSize (l',u') + index (l',u') i'
+        inRange ((l,l'),(u,u')) (i,i')
+                = inRange (l,u) i && inRange (l',u') i'
+
+-- Instances for other tuples are obtained from this scheme:
+--
+--  instance  (Ix a1, Ix a2, ... , Ix ak) => Ix (a1,a2,...,ak)  where
+--      range ((l1,l2,...,lk),(u1,u2,...,uk)) =
+--          [(i1,i2,...,ik) | i1 <- range (l1,u1),
+--                            i2 <- range (l2,u2),
+--                            ...
+--                            ik <- range (lk,uk)]
+--
+--      index ((l1,l2,...,lk),(u1,u2,...,uk)) (i1,i2,...,ik) =
+--        index (lk,uk) ik + rangeSize (lk,uk) * (
+--         index (lk-1,uk-1) ik-1 + rangeSize (lk-1,uk-1) * (
+--          ...
+--           index (l1,u1)))
+--
+--      inRange ((l1,l2,...lk),(u1,u2,...,uk)) (i1,i2,...,ik) =
+--          inRange (l1,u1) i1 && inRange (l2,u2) i2 &&
+--              ... && inRange (lk,uk) ik
+@
+}
+\ecaption{Derivation of Ix instances}
+\label{prelude-index}
+\indextt{Ix}                                                
+\indextt{range}\indextt{index}\indextt{inRange}   
+\indextt{rangeSize}                                         
+\end{figure}
+
+\clearpage
+\subsection{Library {\tt Ix}}
+\inputHS{lib-code/Ix}
+
+%**~footer
index a00d9ae..08b13a8 100644 (file)
@@ -1,5 +1,5 @@
 %
-% $Header: /home/cvs/root/haskell-report/report/lexemes.verb,v 1.11 2002/12/02 11:22:02 simonpj Exp $
+% $Header: /home/cvs/root/haskell-report/report/lexemes.verb,v 1.12 2002/12/02 14:53:30 simonpj Exp $
 %
 %*section 2
 %**<title>Haskell 98 Lexical Structure</title>
@@ -446,7 +446,7 @@ tuple was detected, and (c)~the close brace at the very end, inserted
 because of the column 0 indentation of the end-of-file token.
 
 \begin{figure}
-\outlinec{
+\outlinec{\small
 @
 module AStack( Stack, push, pop, top, size ) where
 data Stack a = Empty 
@@ -471,7 +471,7 @@ top (MkStack x s) = x                     -- (top Empty) is an error
 %**<div align=center> <h4>Figure 1</h4> </div>
 \ecaption{A sample program}
 \label{layout-before}
-\outlinec{
+\outlinec{\small
 @
 module AStack( Stack, push, pop, top, size ) where
 {data Stack a = Empty 
diff --git a/report/lib-code/Array.hs b/report/lib-code/Array.hs
new file mode 100644 (file)
index 0000000..ad100bf
--- /dev/null
@@ -0,0 +1,85 @@
+module  Array ( 
+    module Ix,  -- export all of Ix 
+    Array, array, listArray, (!), bounds, indices, elems, assocs, 
+    accumArray, (//), accum, ixmap ) where
+
+import Ix
+import List( (\\) )
+
+infixl 9  !, //
+
+data (Ix a) => Array a b = MkArray (a,a) (a -> b) deriving ()
+
+array       :: (Ix a) => (a,a) -> [(a,b)] -> Array a b
+array b ivs =
+    if and [inRange b i | (i,_) <- ivs]
+        then MkArray b
+                     (\j -> case [v | (i,v) <- ivs, i == j] of
+                            [v]   -> v
+                            []    -> error "Array.!: \
+                                           \undefined array element"
+                            _     -> error "Array.!: \
+                                           \multiply defined array element")
+        else error "Array.array: out-of-range array association"
+
+listArray             :: (Ix a) => (a,a) -> [b] -> Array a b
+listArray b vs        =  array b (zipWith (\ a b -> (a,b)) (range b) vs)
+
+(!)                   :: (Ix a) => Array a b -> a -> b
+(!) (MkArray _ f)     =  f
+
+bounds                :: (Ix a) => Array a b -> (a,a)
+bounds (MkArray b _)  =  b
+
+indices               :: (Ix a) => Array a b -> [a]
+indices               =  range . bounds
+
+elems                 :: (Ix a) => Array a b -> [b]
+elems a               =  [a!i | i <- indices a]
+
+assocs                :: (Ix a) => Array a b -> [(a,b)]
+assocs a              =  [(i, a!i) | i <- indices a]
+
+(//)                  :: (Ix a) => Array a b -> [(a,b)] -> Array a b
+a // new_ivs          = array (bounds a) (old_ivs ++ new_ivs)
+                      where
+                       old_ivs = [(i,a!i) | i <- indices a,
+                                             i `notElem` new_is]
+                       new_is  = [i | (i,_) <- new_ivs]
+
+accum                 :: (Ix a) => (b -> c -> b) -> Array a b -> [(a,c)]
+                                   -> Array a b
+accum f               =  foldl (\a (i,v) -> a // [(i,f (a!i) v)])
+
+accumArray            :: (Ix a) => (b -> c -> b) -> b -> (a,a) -> [(a,c)]
+                                   -> Array a b
+accumArray f z b      =  accum f (array b [(i,z) | i <- range b])
+
+ixmap                 :: (Ix a, Ix b) => (a,a) -> (a -> b) -> Array b c
+                                         -> Array a c
+ixmap b f a           = array b [(i, a ! f i) | i <- range b]
+
+instance  (Ix a)          => Functor (Array a) where
+    fmap fn (MkArray b f) =  MkArray b (fn . f) 
+
+instance  (Ix a, Eq b)  => Eq (Array a b)  where
+    a == a' =  assocs a == assocs a'
+
+instance  (Ix a, Ord b) => Ord (Array a b)  where
+    a <= a' =  assocs a <= assocs a'
+
+instance  (Ix a, Show a, Show b) => Show (Array a b)  where
+    showsPrec p a = showParen (p > arrPrec) (
+                    showString "array " .
+                    showsPrec (arrPrec+1) (bounds a) . showChar ' ' .
+                    showsPrec (arrPrec+1) (assocs a)                  )
+
+instance  (Ix a, Read a, Read b) => Read (Array a b)  where
+    readsPrec p = readParen (p > arrPrec)
+           (\r -> [ (array b as, u) 
+                  | ("array",s) <- lex r,
+                    (b,t)       <- readsPrec (arrPrec+1) s,
+                    (as,u)      <- readsPrec (arrPrec+1) t ])
+
+-- Precedence of the 'array' function is that of application itself
+arrPrec = 10
diff --git a/report/lib-code/Char.hs b/report/lib-code/Char.hs
new file mode 100644 (file)
index 0000000..ab08471
--- /dev/null
@@ -0,0 +1,157 @@
+module Char ( 
+    isAscii, isLatin1, isControl, isPrint, isSpace, isUpper, isLower,
+    isAlpha, isDigit, isOctDigit, isHexDigit, isAlphaNum,
+    digitToInt, intToDigit,
+    toUpper, toLower,
+    ord, chr,
+    readLitChar, showLitChar, lexLitChar,
+
+        -- ...and what the Prelude exports
+    Char, String
+    ) where
+
+import Array         -- Used for character name table.
+import Numeric (readDec, readOct, lexDigits, readHex)
+import UnicodePrims  -- Source of primitive Unicode functions.
+
+-- Character-testing operations
+isAscii, isLatin1, isControl, isPrint, isSpace, isUpper, isLower,
+ isAlpha, isDigit, isOctDigit, isHexDigit, isAlphaNum :: Char -> Bool
+
+isAscii c                =  c < '\x80'
+
+isLatin1 c               =  c <= '\xff'
+
+isControl c              =  c < ' ' || c >= '\DEL' && c <= '\x9f'
+
+isPrint                  =  primUnicodeIsPrint
+
+isSpace c                =  c `elem` " \t\n\r\f\v\xA0"
+        -- Only Latin-1 spaces recognized
+
+isUpper                  =  primUnicodeIsUpper  -- 'A'..'Z'
+
+isLower                  =  primUnicodeIsLower  -- 'a'..'z'
+
+isAlpha c                =  isUpper c || isLower c
+
+isDigit c                =  c >= '0' && c <= '9'
+
+isOctDigit c             =  c >= '0' && c <= '7'
+
+isHexDigit c             =  isDigit c || c >= 'A' && c <= 'F' ||
+                                         c >= 'a' && c <= 'f'
+
+isAlphaNum               =  primUnicodeIsAlphaNum
+
+
+-- Digit conversion operations
+digitToInt :: Char -> Int
+digitToInt c
+  | isDigit c            =  fromEnum c - fromEnum '0'
+  | c >= 'a' && c <= 'f' =  fromEnum c - fromEnum 'a' + 10
+  | c >= 'A' && c <= 'F' =  fromEnum c - fromEnum 'A' + 10
+  | otherwise            =  error "Char.digitToInt: not a digit"
+
+intToDigit :: Int -> Char
+intToDigit i
+  | i >= 0  && i <=  9   =  toEnum (fromEnum '0' + i)
+  | i >= 10 && i <= 15   =  toEnum (fromEnum 'a' + i - 10)
+  | otherwise            =  error "Char.intToDigit: not a digit"
+
+
+-- Case-changing operations
+toUpper :: Char -> Char
+toUpper =  primUnicodeToUpper
+        
+toLower :: Char -> Char
+toLower =  primUnicodeToLower
+
+-- Character code functions
+ord  :: Char -> Int
+ord  =  fromEnum
+     
+chr  :: Int  -> Char
+chr  =  toEnum
+
+-- Text functions
+readLitChar          :: ReadS Char
+readLitChar ('\\':s) =  readEsc s
+readLitChar (c:s)    =  [(c,s)]
+
+readEsc          :: ReadS Char
+readEsc ('a':s)  = [('\a',s)]
+readEsc ('b':s)  = [('\b',s)]
+readEsc ('f':s)  = [('\f',s)]
+readEsc ('n':s)  = [('\n',s)]
+readEsc ('r':s)  = [('\r',s)]
+readEsc ('t':s)  = [('\t',s)]
+readEsc ('v':s)  = [('\v',s)]
+readEsc ('\\':s) = [('\\',s)]
+readEsc ('"':s)  = [('"',s)]
+readEsc ('\'':s) = [('\'',s)]
+readEsc ('^':c:s) | c >= '@' && c <= '_'
+                 = [(chr (ord c - ord '@'), s)]
+readEsc s@(d:_) | isDigit d
+                 = [(chr n, t) | (n,t) <- readDec s]
+readEsc ('o':s)  = [(chr n, t) | (n,t) <- readOct s]
+readEsc ('x':s)  = [(chr n, t) | (n,t) <- readHex s]
+readEsc s@(c:_) | isUpper c
+                 = let table = ('\DEL', "DEL") : assocs asciiTab
+                   in case [(c,s') | (c, mne) <- table,
+                                     ([],s') <- [match mne s]]
+                      of (pr:_) -> [pr]
+                         []     -> []
+readEsc _        = []
+
+match                         :: (Eq a) => [a] -> [a] -> ([a],[a])
+match (x:xs) (y:ys) | x == y  =  match xs ys
+match xs     ys               =  (xs,ys)
+
+showLitChar               :: Char -> ShowS
+showLitChar c | c > '\DEL' =  showChar '\\' . 
+                              protectEsc isDigit (shows (ord c))
+showLitChar '\DEL'         =  showString "\\DEL"
+showLitChar '\\'           =  showString "\\\\"
+showLitChar c | c >= ' '   =  showChar c
+showLitChar '\a'           =  showString "\\a"
+showLitChar '\b'           =  showString "\\b"
+showLitChar '\f'           =  showString "\\f"
+showLitChar '\n'           =  showString "\\n"
+showLitChar '\r'           =  showString "\\r"
+showLitChar '\t'           =  showString "\\t"
+showLitChar '\v'           =  showString "\\v"
+showLitChar '\SO'          =  protectEsc (== 'H') (showString "\\SO")
+showLitChar c              =  showString ('\\' : asciiTab!c)
+
+protectEsc p f             = f . cont
+                             where cont s@(c:_) | p c = "\\&" ++ s
+                                   cont s             = s
+asciiTab = listArray ('\NUL', ' ')
+           ["NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
+            "BS",  "HT",  "LF",  "VT",  "FF",  "CR",  "SO",  "SI", 
+            "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
+            "CAN", "EM",  "SUB", "ESC", "FS",  "GS",  "RS",  "US", 
+            "SP"] 
+
+lexLitChar          :: ReadS String
+lexLitChar ('\\':s) =  map (prefix '\\') (lexEsc s)
+        where
+          lexEsc (c:s)     | c `elem` "abfnrtv\\\"'" = [([c],s)]
+          lexEsc ('^':c:s) | c >= '@' && c <= '_'    = [(['^',c],s)]
+
+          -- Numeric escapes
+          lexEsc ('o':s)               = [prefix 'o' (span isOctDigit s)]
+          lexEsc ('x':s)               = [prefix 'x' (span isHexDigit s)]
+          lexEsc s@(d:_)   | isDigit d = [span isDigit s]
+
+          -- Very crude approximation to \XYZ.
+          lexEsc s@(c:_)   | isUpper c = [span isCharName s]
+          lexEsc _                     = []
+
+          isCharName c   = isUpper c || isDigit c
+          prefix c (t,s) = (c:t, s)
+
+lexLitChar (c:s)    =  [([c],s)]
+lexLitChar ""       =  []
+
diff --git a/report/lib-code/Complex.hs b/report/lib-code/Complex.hs
new file mode 100644 (file)
index 0000000..cbfaee0
--- /dev/null
@@ -0,0 +1,94 @@
+
+module Complex(Complex((:+)), realPart, imagPart, conjugate, mkPolar,
+               cis, polar, magnitude, phase)  where
+
+infix  6  :+
+
+data  (RealFloat a)     => Complex a = !a :+ !a  deriving (Eq,Read,Show)
+
+
+realPart, imagPart :: (RealFloat a) => Complex a -> a
+realPart (x:+y)         =  x
+imagPart (x:+y)         =  y
+
+conjugate       :: (RealFloat a) => Complex a -> Complex a
+conjugate (x:+y) =  x :+ (-y)
+
+mkPolar                 :: (RealFloat a) => a -> a -> Complex a
+mkPolar r theta         =  r * cos theta :+ r * sin theta
+
+cis             :: (RealFloat a) => a -> Complex a
+cis theta       =  cos theta :+ sin theta
+
+polar           :: (RealFloat a) => Complex a -> (a,a)
+polar z                 =  (magnitude z, phase z)
+
+magnitude :: (RealFloat a) => Complex a -> a
+magnitude (x:+y) =  scaleFloat k
+                    (sqrt ((scaleFloat mk x)^2 + (scaleFloat mk y)^2))
+                   where k  = max (exponent x) (exponent y)
+                         mk = - k
+
+phase :: (RealFloat a) => Complex a -> a
+phase (0 :+ 0) = 0
+phase (x :+ y) = atan2 y x
+
+
+instance  (RealFloat a) => Num (Complex a)  where
+    (x:+y) + (x':+y')  =  (x+x') :+ (y+y')
+    (x:+y) - (x':+y')  =  (x-x') :+ (y-y')
+    (x:+y) * (x':+y')  =  (x*x'-y*y') :+ (x*y'+y*x')
+    negate (x:+y)      =  negate x :+ negate y
+    abs z              =  magnitude z :+ 0
+    signum 0           =  0
+    signum z@(x:+y)    =  x/r :+ y/r  where r = magnitude z
+    fromInteger n      =  fromInteger n :+ 0
+
+instance  (RealFloat a) => Fractional (Complex a)  where
+    (x:+y) / (x':+y')  =  (x*x''+y*y'') / d :+ (y*x''-x*y'') / d
+                          where x'' = scaleFloat k x'
+                                y'' = scaleFloat k y'
+                                k   = - max (exponent x') (exponent y')
+                                d   = x'*x'' + y'*y''
+
+    fromRational a     =  fromRational a :+ 0
+
+instance  (RealFloat a) => Floating (Complex a)        where
+    pi             =  pi :+ 0
+    exp (x:+y)     =  expx * cos y :+ expx * sin y
+                      where expx = exp x
+    log z          =  log (magnitude z) :+ phase z
+
+    sqrt 0         =  0
+    sqrt z@(x:+y)  =  u :+ (if y < 0 then -v else v)
+                      where (u,v) = if x < 0 then (v',u') else (u',v')
+                            v'    = abs y / (u'*2)
+                            u'    = sqrt ((magnitude z + abs x) / 2)
+
+    sin (x:+y)     =  sin x * cosh y :+ cos x * sinh y
+    cos (x:+y)     =  cos x * cosh y :+ (- sin x * sinh y)
+    tan (x:+y)     =  (sinx*coshy:+cosx*sinhy)/(cosx*coshy:+(-sinx*sinhy))
+                      where sinx  = sin x
+                            cosx  = cos x
+                            sinhy = sinh y
+                            coshy = cosh y
+
+    sinh (x:+y)    =  cos y * sinh x :+ sin  y * cosh x
+    cosh (x:+y)    =  cos y * cosh x :+ sin y * sinh x
+    tanh (x:+y)    =  (cosy*sinhx:+siny*coshx)/(cosy*coshx:+siny*sinhx)
+                      where siny  = sin y
+                            cosy  = cos y
+                            sinhx = sinh x
+                            coshx = cosh x
+
+    asin z@(x:+y)  =  y':+(-x')
+                      where  (x':+y') = log (((-y):+x) + sqrt (1 - z*z))
+    acos z@(x:+y)  =  y'':+(-x'')
+                      where (x'':+y'') = log (z + ((-y'):+x'))
+                            (x':+y')   = sqrt (1 - z*z)
+    atan z@(x:+y)  =  y':+(-x')
+                      where (x':+y') = log (((1-y):+x) / sqrt (1+z*z))
+
+    asinh z        =  log (z + sqrt (1+z*z))
+    acosh z        =  log (z + (z+1) * sqrt ((z-1)/(z+1)))
+    atanh z        =  log ((1+z) / sqrt (1-z*z))
diff --git a/report/lib-code/IO.hs b/report/lib-code/IO.hs
new file mode 100644 (file)
index 0000000..6c29939
--- /dev/null
@@ -0,0 +1,28 @@
+module IO {- export list omitted -} where
+
+-- Just provide an implementation of the system-independent
+-- actions that IO exports.
+
+try            :: IO a -> IO (Either IOError a)
+try f          =  catch (do r <- f
+                            return (Right r))
+                        (return . Left)
+
+bracket        :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
+bracket before after m = do
+        x  <- before
+        rs <- try (m x)
+        after x
+        case rs of
+           Right r -> return r
+           Left  e -> ioError e
+
+-- variant of the above where middle computation doesn't want x
+bracket_        :: IO a -> (a -> IO b) -> IO c -> IO c
+bracket_ before after m = do
+         x  <- before
+         rs <- try m
+         after x
+         case rs of
+            Right r -> return r
+            Left  e -> ioError e
diff --git a/report/lib-code/Ix.hs b/report/lib-code/Ix.hs
new file mode 100644 (file)
index 0000000..e379aac
--- /dev/null
@@ -0,0 +1,41 @@
+module Ix ( Ix(range, index, inRange, rangeSize) ) where
+
+class  Ord a => Ix a  where
+    range     :: (a,a) -> [a]
+    index     :: (a,a) -> a -> Int
+    inRange   :: (a,a) -> a -> Bool
+    rangeSize :: (a,a) -> Int
+
+    rangeSize b@(l,h) | null (range b) = 0
+                      | otherwise      = index b h + 1 
+       -- NB: replacing "null (range b)" by  "not (l <= h)"
+       -- fails if the bounds are tuples.  For example,
+       --      (1,2) <= (2,1)
+       -- but the range is nevertheless empty
+       --      range ((1,2),(2,1)) = []
+
+instance  Ix Char  where
+    range (m,n)                = [m..n]
+    index b@(c,c') ci
+        | inRange b ci  =  fromEnum ci - fromEnum c
+        | otherwise     =  error "Ix.index: Index out of range."
+    inRange (c,c') i    =  c <= i && i <= c'
+
+instance  Ix Int  where
+    range (m,n)                = [m..n]
+    index b@(m,n) i
+        | inRange b i   =  i - m
+        | otherwise     =  error "Ix.index: Index out of range."
+    inRange (m,n) i     =  m <= i && i <= n
+
+instance  Ix Integer  where
+    range (m,n)                = [m..n]
+    index b@(m,n) i
+        | inRange b i   =  fromInteger (i - m)
+        | otherwise     =  error "Ix.index: Index out of range."
+    inRange (m,n) i     =  m <= i && i <= n
+
+instance (Ix a,Ix b) => Ix (a, b) -- as derived, for all tuples
+instance Ix Bool                  -- as derived
+instance Ix Ordering              -- as derived
+instance Ix ()                    -- as derived
diff --git a/report/lib-code/List.hs b/report/lib-code/List.hs
new file mode 100644 (file)
index 0000000..0300b1b
--- /dev/null
@@ -0,0 +1,270 @@
+module List ( 
+    elemIndex, elemIndices,
+    find, findIndex, findIndices,
+    nub, nubBy, delete, deleteBy, (\\), deleteFirstsBy,
+    union, unionBy, intersect, intersectBy,
+    intersperse, transpose, partition, group, groupBy,
+    inits, tails, isPrefixOf, isSuffixOf,
+    mapAccumL, mapAccumR,
+    sort, sortBy, insert, insertBy, maximumBy, minimumBy,
+    genericLength, genericTake, genericDrop,
+    genericSplitAt, genericIndex, genericReplicate,
+    zip4, zip5, zip6, zip7,
+    zipWith4, zipWith5, zipWith6, zipWith7,
+    unzip4, unzip5, unzip6, unzip7, unfoldr,
+
+    -- ...and what the Prelude exports
+    -- []((:), []),    -- This is built-in syntax
+    map, (++), concat, filter,
+    head, last, tail, init, null, length, (!!),
+    foldl, foldl1, scanl, scanl1, foldr, foldr1, scanr, scanr1,
+    iterate, repeat, replicate, cycle,
+    take, drop, splitAt, takeWhile, dropWhile, span, break,
+    lines, words, unlines, unwords, reverse, and, or,
+    any, all, elem, notElem, lookup,
+    sum, product, maximum, minimum, concatMap, 
+    zip, zip3, zipWith, zipWith3, unzip, unzip3
+    ) where
+
+import Maybe( listToMaybe )
+
+infix 5 \\
+
+elemIndex               :: Eq a => a -> [a] -> Maybe Int
+elemIndex x             =  findIndex (x ==)
+        
+elemIndices             :: Eq a => a -> [a] -> [Int]
+elemIndices x           =  findIndices (x ==)
+                        
+find                    :: (a -> Bool) -> [a] -> Maybe a
+find p                  =  listToMaybe . filter p
+
+findIndex               :: (a -> Bool) -> [a] -> Maybe Int
+findIndex p             =  listToMaybe . findIndices p
+
+findIndices             :: (a -> Bool) -> [a] -> [Int]
+findIndices p xs        =  [ i | (x,i) <- zip xs [0..], p x ]
+
+nub                     :: Eq a => [a] -> [a]
+nub                     =  nubBy (==)
+
+nubBy                   :: (a -> a -> Bool) -> [a] -> [a]
+nubBy eq []             =  []
+nubBy eq (x:xs)         =  x : nubBy eq (filter (\y -> not (eq x y)) xs)
+
+delete                  :: Eq a => a -> [a] -> [a]
+delete                  =  deleteBy (==)
+
+deleteBy                :: (a -> a -> Bool) -> a -> [a] -> [a]
+deleteBy eq x []        = []
+deleteBy eq x (y:ys)    = if x `eq` y then ys else y : deleteBy eq x ys
+
+(\\)                    :: Eq a => [a] -> [a] -> [a]
+(\\)                    =  foldl (flip delete)
+
+deleteFirstsBy          :: (a -> a -> Bool) -> [a] -> [a] -> [a]
+deleteFirstsBy eq       =  foldl (flip (deleteBy eq))
+
+union                   :: Eq a => [a] -> [a] -> [a]
+union                   =  unionBy (==)    
+
+unionBy                 :: (a -> a -> Bool) -> [a] -> [a] -> [a]
+unionBy eq xs ys        =  xs ++ deleteFirstsBy eq (nubBy eq ys) xs
+
+intersect               :: Eq a => [a] -> [a] -> [a]
+intersect               =  intersectBy (==)
+
+intersectBy             :: (a -> a -> Bool) -> [a] -> [a] -> [a]
+intersectBy eq xs ys    =  [x | x <- xs, any (eq x) ys]
+
+intersperse             :: a -> [a] -> [a]
+intersperse sep []      =  []
+intersperse sep [x]     =  [x]
+intersperse sep (x:xs)  =  x : sep : intersperse sep xs
+
+-- transpose is lazy in both rows and columns,
+--       and works for non-rectangular 'matrices'
+-- For example, transpose [[1,2],[3,4,5],[]]  =  [[1,3],[2,4],[5]]
+-- Note that [h | (h:t) <- xss] is not the same as (map head xss)
+--      because the former discards empty sublists inside xss
+transpose                :: [[a]] -> [[a]]
+transpose []             = []
+transpose ([]     : xss) = transpose xss
+transpose ((x:xs) : xss) = (x : [h | (h:t) <- xss]) : 
+                           transpose (xs : [t | (h:t) <- xss])
+
+partition               :: (a -> Bool) -> [a] -> ([a],[a])
+partition p xs          =  (filter p xs, filter (not . p) xs)
+
+-- group splits its list argument into a list of lists of equal, adjacent
+-- elements.  e.g.,
+-- group "Mississippi" == ["M","i","ss","i","ss","i","pp","i"]
+group                   :: Eq a => [a] -> [[a]]
+group                   =  groupBy (==)
+
+groupBy                 :: (a -> a -> Bool) -> [a] -> [[a]]
+groupBy eq []           =  []
+groupBy eq (x:xs)       =  (x:ys) : groupBy eq zs
+                           where (ys,zs) = span (eq x) xs
+
+-- inits xs returns the list of initial segments of xs, shortest first.
+-- e.g., inits "abc" == ["","a","ab","abc"]
+inits                   :: [a] -> [[a]]
+inits []                =  [[]]
+inits (x:xs)            =  [[]] ++ map (x:) (inits xs)
+
+-- tails xs returns the list of all final segments of xs, longest first.
+-- e.g., tails "abc" == ["abc", "bc", "c",""]
+tails                   :: [a] -> [[a]]
+tails []                =  [[]]
+tails xxs@(_:xs)        =  xxs : tails xs
+
+isPrefixOf               :: Eq a => [a] -> [a] -> Bool
+isPrefixOf []     _      =  True
+isPrefixOf _      []     =  False
+isPrefixOf (x:xs) (y:ys) =  x == y && isPrefixOf xs ys
+
+isSuffixOf              :: Eq a => [a] -> [a] -> Bool
+isSuffixOf x y          =  reverse x `isPrefixOf` reverse y
+
+mapAccumL               :: (a -> b -> (a, c)) -> a -> [b] -> (a, [c])
+mapAccumL f s []        =  (s, [])
+mapAccumL f s (x:xs)    =  (s'',y:ys)
+                           where (s', y ) = f s x
+                                 (s'',ys) = mapAccumL f s' xs
+
+mapAccumR               :: (a -> b -> (a, c)) -> a -> [b] -> (a, [c])
+mapAccumR f s []        =  (s, [])
+mapAccumR f s (x:xs)    =  (s'', y:ys)
+                           where (s'',y ) = f s' x
+                                 (s', ys) = mapAccumR f s xs
+
+unfoldr                 :: (b -> Maybe (a,b)) -> b -> [a]
+unfoldr f b             = case f b of
+                                Nothing    -> []
+                                Just (a,b) -> a : unfoldr f b
+
+sort                    :: (Ord a) => [a] -> [a]
+sort                    =  sortBy compare
+
+sortBy                  :: (a -> a -> Ordering) -> [a] -> [a]
+sortBy cmp              =  foldr (insertBy cmp) []
+
+insert                  :: (Ord a) => a -> [a] -> [a]
+insert                  = insertBy compare
+
+insertBy                :: (a -> a -> Ordering) -> a -> [a] -> [a]
+insertBy cmp x []       =  [x]
+insertBy cmp x ys@(y:ys')
+                        =  case cmp x y of
+                                GT -> y : insertBy cmp x ys'
+                                _  -> x : ys
+
+maximumBy               :: (a -> a -> Ordering) -> [a] -> a
+maximumBy cmp []        =  error "List.maximumBy: empty list"
+maximumBy cmp xs        =  foldl1 max xs
+                        where
+                           max x y = case cmp x y of
+                                        GT -> x
+                                        _  -> y
+
+minimumBy               :: (a -> a -> Ordering) -> [a] -> a
+minimumBy cmp []        =  error "List.minimumBy: empty list"
+minimumBy cmp xs        =  foldl1 min xs
+                        where
+                           min x y = case cmp x y of
+                                        GT -> y
+                                        _  -> x
+
+genericLength           :: (Integral a) => [b] -> a
+genericLength []        =  0
+genericLength (x:xs)    =  1 + genericLength xs
+
+genericTake             :: (Integral a) => a -> [b] -> [b]
+genericTake _ []        =  []
+genericTake 0 _         =  []
+genericTake n (x:xs) 
+   | n > 0              =  x : genericTake (n-1) xs
+   | otherwise          =  error "List.genericTake: negative argument"
+
+genericDrop             :: (Integral a) => a -> [b] -> [b]
+genericDrop 0 xs        =  xs
+genericDrop _ []        =  []
+genericDrop n (_:xs) 
+   | n > 0              =  genericDrop (n-1) xs
+   | otherwise          =  error "List.genericDrop: negative argument"
+
+genericSplitAt          :: (Integral a) => a -> [b] -> ([b],[b])
+genericSplitAt 0 xs     =  ([],xs)
+genericSplitAt _ []     =  ([],[])
+genericSplitAt n (x:xs) 
+   | n > 0              =  (x:xs',xs'')
+   | otherwise          =  error "List.genericSplitAt: negative argument"
+       where (xs',xs'') =  genericSplitAt (n-1) xs
+
+genericIndex            :: (Integral a) => [b] -> a -> b
+genericIndex (x:_)  0   =  x
+genericIndex (_:xs) n 
+        | n > 0         =  genericIndex xs (n-1)
+        | otherwise     =  error "List.genericIndex: negative argument"
+genericIndex _ _        =  error "List.genericIndex: index too large"
+
+genericReplicate        :: (Integral a) => a -> b -> [b]
+genericReplicate n x    =  genericTake n (repeat x)
+zip4                    :: [a] -> [b] -> [c] -> [d] -> [(a,b,c,d)]
+zip4                    =  zipWith4 (,,,)
+
+zip5                    :: [a] -> [b] -> [c] -> [d] -> [e] -> [(a,b,c,d,e)]
+zip5                    =  zipWith5 (,,,,)
+
+zip6                    :: [a] -> [b] -> [c] -> [d] -> [e] -> [f] -> 
+                              [(a,b,c,d,e,f)]
+zip6                    =  zipWith6 (,,,,,)
+
+zip7                    :: [a] -> [b] -> [c] -> [d] -> [e] -> [f] ->
+                              [g] -> [(a,b,c,d,e,f,g)]
+zip7                    =  zipWith7 (,,,,,,)
+
+zipWith4                :: (a->b->c->d->e) -> [a]->[b]->[c]->[d]->[e]
+zipWith4 z (a:as) (b:bs) (c:cs) (d:ds)
+                        =  z a b c d : zipWith4 z as bs cs ds
+zipWith4 _ _ _ _ _      =  []
+
+zipWith5                :: (a->b->c->d->e->f) -> 
+                           [a]->[b]->[c]->[d]->[e]->[f]
+zipWith5 z (a:as) (b:bs) (c:cs) (d:ds) (e:es)
+                        =  z a b c d e : zipWith5 z as bs cs ds es
+zipWith5 _ _ _ _ _ _    =  []
+
+zipWith6                :: (a->b->c->d->e->f->g) ->
+                           [a]->[b]->[c]->[d]->[e]->[f]->[g]
+zipWith6 z (a:as) (b:bs) (c:cs) (d:ds) (e:es) (f:fs)
+                        =  z a b c d e f : zipWith6 z as bs cs ds es fs
+zipWith6 _ _ _ _ _ _ _  =  []
+
+zipWith7                :: (a->b->c->d->e->f->g->h) ->
+                           [a]->[b]->[c]->[d]->[e]->[f]->[g]->[h]
+zipWith7 z (a:as) (b:bs) (c:cs) (d:ds) (e:es) (f:fs) (g:gs)
+                   =  z a b c d e f g : zipWith7 z as bs cs ds es fs gs
+zipWith7 _ _ _ _ _ _ _ _ = []
+
+unzip4                  :: [(a,b,c,d)] -> ([a],[b],[c],[d])
+unzip4                  =  foldr (\(a,b,c,d) ~(as,bs,cs,ds) ->
+                                        (a:as,b:bs,c:cs,d:ds))
+                                 ([],[],[],[])
+
+unzip5                  :: [(a,b,c,d,e)] -> ([a],[b],[c],[d],[e])
+unzip5                  =  foldr (\(a,b,c,d,e) ~(as,bs,cs,ds,es) ->
+                                        (a:as,b:bs,c:cs,d:ds,e:es))
+                                 ([],[],[],[],[])
+
+unzip6                  :: [(a,b,c,d,e,f)] -> ([a],[b],[c],[d],[e],[f])
+unzip6                  =  foldr (\(a,b,c,d,e,f) ~(as,bs,cs,ds,es,fs) ->
+                                        (a:as,b:bs,c:cs,d:ds,e:es,f:fs))
+                                 ([],[],[],[],[],[])
+
+unzip7          :: [(a,b,c,d,e,f,g)] -> ([a],[b],[c],[d],[e],[f],[g])
+unzip7          =  foldr (\(a,b,c,d,e,f,g) ~(as,bs,cs,ds,es,fs,gs) ->
+                                (a:as,b:bs,c:cs,d:ds,e:es,f:fs,g:gs))
+                         ([],[],[],[],[],[],[])
diff --git a/report/lib-code/Locale.hs b/report/lib-code/Locale.hs
new file mode 100644 (file)
index 0000000..b56a648
--- /dev/null
@@ -0,0 +1,30 @@
+module Locale(TimeLocale(..), defaultTimeLocale) where
+
+data TimeLocale = TimeLocale {
+        wDays  :: [(String, String)],   -- full and abbreviated week days
+        months :: [(String, String)],   -- full and abbreviated months
+        amPm   :: (String, String),     -- AM/PM symbols
+        dateTimeFmt, dateFmt,           -- formatting strings
+          timeFmt, time12Fmt :: String     
+        } deriving (Eq, Ord, Show)
+
+defaultTimeLocale :: TimeLocale 
+defaultTimeLocale =  TimeLocale { 
+        wDays  = [("Sunday",   "Sun"),  ("Monday",    "Mon"),   
+                  ("Tuesday",  "Tue"),  ("Wednesday", "Wed"), 
+                  ("Thursday", "Thu"),  ("Friday",    "Fri"), 
+                  ("Saturday", "Sat")],
+
+        months = [("January",   "Jan"), ("February",  "Feb"),
+                  ("March",     "Mar"), ("April",     "Apr"),
+                  ("May",       "May"), ("June",      "Jun"),
+                  ("July",      "Jul"), ("August",    "Aug"),
+                  ("September", "Sep"), ("October",   "Oct"),
+                  ("November",  "Nov"), ("December",  "Dec")],
+
+        amPm = ("AM", "PM"),
+        dateTimeFmt = "%a %b %e %H:%M:%S %Z %Y",
+        dateFmt = "%m/%d/%y",
+        timeFmt = "%H:%M:%S",
+        time12Fmt = "%I:%M:%S %p"
+        }
diff --git a/report/lib-code/Maybe.hs b/report/lib-code/Maybe.hs
new file mode 100644 (file)
index 0000000..f1eac52
--- /dev/null
@@ -0,0 +1,38 @@
+module Maybe(
+    isJust, isNothing,
+    fromJust, fromMaybe, listToMaybe, maybeToList,
+    catMaybes, mapMaybe,
+
+    -- ...and what the Prelude exports
+    Maybe(Nothing, Just),
+    maybe
+  ) where
+
+isJust                 :: Maybe a -> Bool
+isJust (Just a)        =  True
+isJust Nothing         =  False
+
+isNothing             :: Maybe a -> Bool
+isNothing             =  not . isJust
+
+fromJust               :: Maybe a -> a
+fromJust (Just a)      =  a
+fromJust Nothing       =  error "Maybe.fromJust: Nothing"
+
+fromMaybe              :: a -> Maybe a -> a
+fromMaybe d Nothing    =  d
+fromMaybe d (Just a)   =  a
+
+maybeToList            :: Maybe a -> [a]
+maybeToList Nothing    =  []
+maybeToList (Just a)   =  [a]
+
+listToMaybe            :: [a] -> Maybe a
+listToMaybe []         =  Nothing
+listToMaybe (a:_)      =  Just a
+catMaybes              :: [Maybe a] -> [a]
+catMaybes ms           =  [ m | Just m <- ms ]
+
+mapMaybe               :: (a -> Maybe b) -> [a] -> [b]
+mapMaybe f             =  catMaybes . map f
diff --git a/report/lib-code/Monad.hs b/report/lib-code/Monad.hs
new file mode 100644 (file)
index 0000000..6d63563
--- /dev/null
@@ -0,0 +1,97 @@
+module Monad (
+    MonadPlus(mzero, mplus),
+    join, guard, when, unless, ap,
+    msum,
+    filterM, mapAndUnzipM, zipWithM, zipWithM_, foldM, 
+    liftM, liftM2, liftM3, liftM4, liftM5,
+
+    -- ...and what the Prelude exports
+    Monad((>>=), (>>), return, fail),
+    Functor(fmap),
+    mapM, mapM_, sequence, sequence_, (=<<), 
+    ) where
+
+
+-- The MonadPlus class definition
+
+class  (Monad m) => MonadPlus m  where
+    mzero  :: m a
+    mplus  :: m a -> m a -> m a
+
+
+-- Instances of MonadPlus
+
+instance  MonadPlus Maybe  where
+    mzero                 = Nothing
+
+    Nothing `mplus` ys    =  ys
+    xs      `mplus` ys    =  xs
+
+instance  MonadPlus []  where
+    mzero =  []
+    mplus = (++)
+
+
+-- Functions    
+
+
+msum            :: MonadPlus m => [m a] -> m a
+msum xs                 =  foldr mplus mzero xs
+
+join             :: (Monad m) => m (m a) -> m a
+join x           =  x >>= id
+
+when             :: (Monad m) => Bool -> m () -> m ()
+when p s         =  if p then s else return ()
+
+unless           :: (Monad m) => Bool -> m () -> m ()
+unless p s       =  when (not p) s
+
+ap               :: (Monad m) => m (a -> b) -> m a -> m b
+ap               =  liftM2 ($)
+
+guard            :: MonadPlus m => Bool -> m ()
+guard p          =  if p then return () else mzero
+
+mapAndUnzipM     :: (Monad m) => (a -> m (b,c)) -> [a] -> m ([b], [c])
+mapAndUnzipM f xs = sequence (map f xs) >>= return . unzip
+
+zipWithM         :: (Monad m) => (a -> b -> m c) -> [a] -> [b] -> m [c]
+zipWithM f xs ys =  sequence (zipWith f xs ys)
+
+zipWithM_         :: (Monad m) => (a -> b -> m c) -> [a] -> [b] -> m ()
+zipWithM_ f xs ys =  sequence_ (zipWith f xs ys)
+
+foldM            :: (Monad m) => (a -> b -> m a) -> a -> [b] -> m a
+foldM f a []     =  return a
+foldM f a (x:xs) =  f a x >>= \ y -> foldM f y xs
+
+filterM :: Monad m => (a -> m Bool) -> [a] -> m [a]
+filterM p []     = return []
+filterM p (x:xs) = do { b  <- p x;
+                       ys <- filterM p xs; 
+                       return (if b then (x:ys) else ys)
+                  }
+
+liftM            :: (Monad m) => (a -> b) -> (m a -> m b)
+liftM f          =  \a -> do { a' <- a; return (f a') }
+
+liftM2           :: (Monad m) => (a -> b -> c) -> (m a -> m b -> m c)
+liftM2 f         =  \a b -> do { a' <- a; b' <- b; return (f a' b') }
+
+liftM3           :: (Monad m) => (a -> b -> c -> d) ->
+                                 (m a -> m b -> m c -> m d)
+liftM3 f         =  \a b c -> do { a' <- a; b' <- b; c' <- c;
+                                  return (f a' b' c') }
+
+liftM4           :: (Monad m) => (a -> b -> c -> d -> e) ->
+                                 (m a -> m b -> m c -> m d -> m e)
+liftM4 f         =  \a b c d -> do { a' <- a; b' <- b; c' <- c; d' <- d;
+                                    return (f a' b' c' d') }
+
+liftM5           :: (Monad m) => (a -> b -> c -> d -> e -> f) ->
+                                 (m a -> m b -> m c -> m d -> m e -> m f)
+liftM5 f         =  \a b c d e -> do { a' <- a; b' <- b; c' <- c; d' <- d;
+                                      e' <- e; return (f a' b' c' d' e') }
+
+
diff --git a/report/lib-code/Numeric.hs b/report/lib-code/Numeric.hs
new file mode 100644 (file)
index 0000000..9dcf496
--- /dev/null
@@ -0,0 +1,341 @@
+module Numeric(fromRat,
+               showSigned, showIntAtBase,
+               showInt, showOct, showHex,
+               readSigned, readInt,
+               readDec, readOct, readHex, 
+               floatToDigits,
+               showEFloat, showFFloat, showGFloat, showFloat, 
+               readFloat, lexDigits) where
+
+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.
+
+fromRat :: (RealFloat a) => Rational -> a
+fromRat x = 
+    if x == 0 then encodeFloat 0 0              -- Handle exceptional cases
+    else if x < 0 then - fromRat' (-x)          -- first.
+    else fromRat' x
+
+-- Conversion process:
+-- Scale the rational number by the RealFloat base until
+-- it lies in the range of the mantissa (as used by decodeFloat/encodeFloat).
+-- Then round the rational to an Integer and encode it with the exponent
+-- that we got from the scaling.
+-- To speed up the scaling process we compute the log2 of the number to get
+-- a first guess of the exponent.
+fromRat' :: (RealFloat a) => Rational -> a
+fromRat' x = r
+  where b = floatRadix r
+        p = floatDigits r
+        (minExp0, _) = floatRange r
+        minExp = minExp0 - p            -- the real minimum exponent
+        xMin = toRational (expt b (p-1))
+        xMax = toRational (expt b p)
+        p0 = (integerLogBase b (numerator x) -
+              integerLogBase b (denominator x) - p) `max` minExp
+        f = if p0 < 0 then 1 % expt b (-p0) else expt b p0 % 1
+        (x', p') = scaleRat (toRational b) minExp xMin xMax p0 (x / f)
+        r = encodeFloat (round x') p'
+
+-- Scale x until xMin <= x < xMax, or p (the exponent) <= minExp.
+scaleRat :: Rational -> Int -> Rational -> Rational -> 
+             Int -> Rational -> (Rational, Int)
+scaleRat b minExp xMin xMax p x =
+    if p <= minExp then
+        (x, p)
+    else if x >= xMax then
+        scaleRat b minExp xMin xMax (p+1) (x/b)
+    else if x < xMin  then
+        scaleRat b minExp xMin xMax (p-1) (x*b)
+    else
+        (x, p)
+
+-- Exponentiation with a cache for the most common numbers.
+minExpt = 0::Int
+maxExpt = 1100::Int
+expt :: Integer -> Int -> Integer
+expt base n =
+    if base == 2 && n >= minExpt && n <= maxExpt then
+        expts!n
+    else
+        base^n
+
+expts :: Array Int Integer
+expts = array (minExpt,maxExpt) [(n,2^n) | n <- [minExpt .. maxExpt]]
+
+-- Compute the (floor of the) log of i in base b.
+-- Simplest way would be just divide i by b until it's smaller then b,
+-- but that would be very slow!  We are just slightly more clever.
+integerLogBase :: Integer -> Integer -> Int
+integerLogBase b i =
+     if i < b then
+        0
+     else
+        -- Try squaring the base first to cut down the number of divisions.
+        let l = 2 * integerLogBase (b*b) i
+            doDiv :: Integer -> Int -> Int
+            doDiv i l = if i < b then l else doDiv (i `div` b) (l+1)
+        in  doDiv (i `div` (b^l)) l
+
+
+-- Misc utilities to show integers and floats 
+
+showSigned :: Real a => (a -> ShowS) -> Int -> a -> ShowS
+showSigned showPos p x 
+  | x < 0     = showParen (p > 6) (showChar '-' . showPos (-x))
+  | otherwise = showPos x
+
+-- showInt, showOct, showHex are used for positive numbers only
+showInt, showOct, showHex :: Integral a => a -> ShowS
+showOct = showIntAtBase  8 intToDigit
+showInt = showIntAtBase 10 intToDigit
+showHex = showIntAtBase 16 intToDigit
+
+showIntAtBase :: Integral a 
+             => a              -- base
+             -> (Int -> Char)  -- digit to char
+             -> a              -- number to show
+             -> ShowS
+showIntAtBase base intToDig n rest
+  | n < 0     = error "Numeric.showIntAtBase: can't show negative numbers"
+  | n' == 0   = rest'
+  | otherwise = showIntAtBase base intToDig n' rest'
+  where
+    (n',d) = quotRem n base
+    rest'  = intToDig (fromIntegral d) : rest
+
+
+readSigned :: (Real a) => ReadS a -> ReadS a
+readSigned readPos = readParen False read'
+                     where read' r  = read'' r ++
+                                      [(-x,t) | ("-",s) <- lex r,
+                                                (x,t)   <- read'' s]
+                           read'' r = [(n,s)  | (str,s) <- lex r,
+                                                (n,"")  <- readPos str]
+
+
+-- readInt reads a string of digits using an arbitrary base.  
+-- Leading minus signs must be handled elsewhere.
+
+readInt :: (Integral a) => a -> (Char -> Bool) -> (Char -> Int) -> ReadS a
+readInt radix isDig digToInt s =
+   [(foldl1 (\n d -> n * radix + d) (map (fromIntegral . digToInt) ds), r)
+          | (ds,r) <- nonnull isDig s ]
+
+-- Unsigned readers for various bases
+readDec, readOct, readHex :: (Integral a) => ReadS a
+readDec = readInt 10 isDigit    digitToInt
+readOct = readInt  8 isOctDigit digitToInt
+readHex = readInt 16 isHexDigit digitToInt
+
+
+showEFloat     :: (RealFloat a) => Maybe Int -> a -> ShowS
+showFFloat     :: (RealFloat a) => Maybe Int -> a -> ShowS
+showGFloat     :: (RealFloat a) => Maybe Int -> a -> ShowS
+showFloat      :: (RealFloat a) => a -> ShowS
+
+showEFloat d x =  showString (formatRealFloat FFExponent d x)
+showFFloat d x =  showString (formatRealFloat FFFixed d x)
+showGFloat d x =  showString (formatRealFloat FFGeneric d x)
+showFloat      =  showGFloat Nothing 
+
+-- These are the format types.  This type is not exported.
+
+data FFFormat = FFExponent | FFFixed | FFGeneric
+
+formatRealFloat :: (RealFloat a) => FFFormat -> Maybe Int -> a -> String
+formatRealFloat fmt decs x 
+  = s
+  where 
+    base = 10
+    s = if isNaN x then 
+            "NaN"
+        else if isInfinite x then 
+            if x < 0 then "-Infinity" else "Infinity"
+        else if x < 0 || isNegativeZero x then 
+            '-' : doFmt fmt (floatToDigits (toInteger base) (-x))
+        else 
+            doFmt fmt (floatToDigits (toInteger base) x)
+    
+    doFmt fmt (is, e)
+      = let 
+           ds = map intToDigit is
+        in  
+        case fmt of
+          FFGeneric -> 
+              doFmt (if e < 0 || e > 7 then FFExponent else FFFixed)
+                    (is, e)
+          FFExponent ->
+            case decs of
+              Nothing ->
+                case ds of
+                   []    -> "0.0e0"
+                   [d]   -> d : ".0e" ++ show (e-1)
+                   d:ds  -> d : '.' : ds ++ 'e':show (e-1)
+          
+              Just dec ->
+                let dec' = max dec 1 in
+                case is of
+                  [] -> '0':'.':take dec' (repeat '0') ++ "e0"
+                  _ ->
+                    let (ei, is') = roundTo base (dec'+1) is
+                        d:ds = map intToDigit
+                                   (if ei > 0 then init is' else is')
+                    in d:'.':ds  ++ "e" ++ show (e-1+ei)
+          
+          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  
+    
+              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
+                (0, is) -> (0, is)
+                (1, is) -> (1, 1 : is)
+  where b2 = base `div` 2
+        f n [] = (0, replicate n 0)
+        f 0 (i:_) = (if i >= b2 then 1 else 0, [])
+        f d (i:is) = 
+            let (c, ds) = f (d-1) is
+                i' = c + i
+            in  if i' == base then (1, 0:ds) else (0, i':ds)
+
+--
+-- Based on "Printing Floating-Point Numbers Quickly and Accurately"
+-- by R.G. Burger and R. K. Dybvig, in PLDI 96.
+-- The version here uses a much slower logarithm estimator.  
+-- It should be improved.
+
+-- This function returns a non-empty list of digits (Ints in [0..base-1])
+-- and an exponent.  In general, if
+--      floatToDigits r = ([a, b, ... z], e)
+-- then
+--      r = 0.ab..z * base^e
+-- 
+
+floatToDigits :: (RealFloat a) => Integer -> a -> ([Int], Int)
+
+floatToDigits _ 0 = ([], 0)
+floatToDigits base x =
+    let (f0, e0) = decodeFloat x
+        (minExp0, _) = floatRange x
+        p = floatDigits x
+        b = floatRadix x
+        minExp = minExp0 - p            -- the real minimum exponent
+
+        -- Haskell requires that f be adjusted so denormalized numbers
+        -- will have an impossibly low exponent.  Adjust for this.
+        f :: Integer
+        e :: Int
+        (f, e) = let n = minExp - e0
+                 in  if n > 0 then (f0 `div` (b^n), e0+n) else (f0, e0)
+
+        (r, s, mUp, mDn) =
+           if e >= 0 then
+               let be = b^e in
+               if f == b^(p-1) then
+                   (f*be*b*2, 2*b, be*b, b)
+               else
+                   (f*be*2, 2, be, be)
+           else
+               if e > minExp && f == b^(p-1) then
+                   (f*b*2, b^(-e+1)*2, b, 1)
+               else
+                   (f*2, b^(-e)*2, 1, 1)
+        k = 
+            let k0 =
+                    if b==2 && base==10 then
+                        -- logBase 10 2 is slightly bigger than 3/10 so
+                        -- the following will err on the low side.  Ignoring
+                        -- the fraction will make it err even more.
+                        -- Haskell promises that p-1 <= logBase b f < p.
+                        (p - 1 + e0) * 3 `div` 10
+                    else
+                        ceiling ((log (fromInteger (f+1)) + 
+                                 fromIntegral e * log (fromInteger b)) / 
+                                  log (fromInteger base))
+                fixup n =
+                    if n >= 0 then
+                        if r + mUp <= expt base n * s then n else fixup (n+1)
+                    else
+                        if expt base (-n) * (r + mUp) <= s then n
+                                                           else fixup (n+1)
+            in  fixup k0
+
+        gen ds rn sN mUpN mDnN =
+            let (dn, rn') = (rn * base) `divMod` sN
+                mUpN' = mUpN * base
+                mDnN' = mDnN * base
+            in  case (rn' < mDnN', rn' + mUpN' > sN) of
+                (True,  False) -> dn : ds
+                (False, True)  -> dn+1 : ds
+                (True,  True)  -> if rn' * 2 < sN then dn : ds else dn+1 : ds
+                (False, False) -> gen (dn:ds) rn' sN mUpN' mDnN'
+        rds =
+            if k >= 0 then
+                gen [] r (s * expt base k) mUp mDn
+            else
+                let bk = expt base (-k)
+                in  gen [] (r * bk) s (mUp * bk) (mDn * bk)
+    in  (map fromIntegral (reverse rds), k)
+
+
+
+-- This floating point reader uses a less restrictive syntax for floating
+-- point than the Haskell lexer.  The `.' is optional.
+
+readFloat     :: (RealFrac a) => ReadS a
+readFloat r    = [(fromRational ((n%1)*10^^(k-d)),t) | (n,d,s) <- readFix r,
+                                                       (k,t)   <- readExp s] ++
+                 [ (0/0, t) | ("NaN",t)      <- lex r] ++
+                 [ (1/0, t) | ("Infinity",t) <- lex r]
+               where 
+                 readFix r = [(read (ds++ds'), length ds', t)
+                             | (ds,d) <- lexDigits r,
+                               (ds',t) <- lexFrac d ]
+               
+                 lexFrac ('.':ds) = lexDigits ds
+                 lexFrac s        = [("",s)]        
+                 
+                 readExp (e:s) | e `elem` "eE" = readExp' s
+                 readExp s                     = [(0,s)]
+                 
+                 readExp' ('-':s) = [(-k,t) | (k,t) <- readDec s]
+                 readExp' ('+':s) = readDec s
+                 readExp' s       = readDec s
+
+lexDigits        :: ReadS String 
+lexDigits        =  nonnull isDigit
+
+nonnull          :: (Char -> Bool) -> ReadS String
+nonnull p s      =  [(cs,t) | (cs@(_:_),t) <- [span p s]]
+
diff --git a/report/lib-code/Random.hs b/report/lib-code/Random.hs
new file mode 100644 (file)
index 0000000..8a917d7
--- /dev/null
@@ -0,0 +1,113 @@
+module Random (
+       RandomGen(next, split, genRange),
+       StdGen, mkStdGen,
+
+       Random( random,   randomR, 
+               randoms,  randomRs,
+               randomIO, randomRIO ),
+
+       getStdRandom,
+       getStdGen, setStdGen, newStdGen
+  ) where
+       
+---------------- The RandomGen class ---------------------------
+
+class RandomGen g where
+  genRange :: g -> (Int, Int)
+  next     :: g -> (Int, g)
+  split    :: g -> (g, g)      -- May not exist for all RandomGens
+
+
+---------------- A standard instance of RandomGen ---------------
+data StdGen = ...      -- Abstract
+
+instance RandomGen StdGen where ...
+
+-- The show/read instances provide a primitive way to save
+-- the state of a random number generator
+-- It is expected read (show g) == g
+
+instance Read StdGen where ...
+       -- read succeeds on *any* string, not only those
+       -- constructed with show.  Hence you can use any
+       -- string as way to construct a RandomGen.
+       --   - read guarantees to consume a finite portion of
+       --     the string
+       --   - different strings are likely to result in 
+       --     different generators
+
+instance Show StdGen where ...
+
+mkStdGen :: Int -> StdGen
+-- Make a StdGen from an Int.  Different Ints should result
+-- in different generators.
+
+
+---------------- The Random class ---------------------------
+
+class Random a where
+   randomR :: RandomGen g => (a, a) -> g -> (a, g)
+       -- Returns a random value uniformly distributed in [lo,hi]
+       -- It is unspecified what happens if lo > hi
+
+   random  :: RandomGen g => g -> (a, g)
+       -- Return any value of type a.
+       -- For bounded types, the range is normally the whole type
+       -- For Fractional types, the range is normally [0..1]
+       -- For Integer, the range is (arbitrarily) the range of Int
+
+   randomRs :: RandomGen g => (a, a) -> g -> [a]
+   randoms  :: RandomGen g => g -> [a]
+
+   randomIO :: IO a
+   randomRIO :: (a,a) -> IO a
+
+       -- Default methods
+   randoms g = x : randoms g' 
+            where 
+              (x,g') = random g
+   randomRs = ...similar...
+
+   randomIO        = getStdRandom random
+   randomRIO range = getStdRandom (randomR range)
+
+
+instance Random Int     where ...
+instance Random Integer where ...
+instance Random Float   where ...
+instance Random Double  where ...
+instance Random Bool    where ...
+instance Random Char    where ...
+
+
+---------------- The global random generator ---------------------------
+
+-- There is a single, implicit, global random number generator
+-- of type StdGen, held in some global variable maintained by the IO monad
+--
+-- It is initialised non-deterministically; to get
+-- deterministic behaviour use setStdGen.
+
+setStdGen :: StdGen -> IO ()   -- Set the global generator
+getStdGen :: IO StdGen -- Get the global generator
+
+getStdRandom :: (StdGen -> (a, StdGen)) -> IO a
+       -- Use the supplied function to get a value from
+       -- the current global random generator, g, and update the
+       -- global generator with the new generator returned
+getStdRandom f = do
+       g <- getStdGen
+       let (val, g') = f g
+       setStdGen g'
+       return val
+
+newStdGen :: IO StdGen
+       -- Apply split to the current global random generator
+       -- update it with one of the results and return the other
+newStdGen = do
+       g <- getStdGen
+       let (s1,s2) = split g
+       setStdGen s1
+       return s2
+
+
diff --git a/report/lib-code/Ratio.hs b/report/lib-code/Ratio.hs
new file mode 100644 (file)
index 0000000..10b0c84
--- /dev/null
@@ -0,0 +1,99 @@
+-- Standard functions on rational numbers
+
+module  Ratio (
+    Ratio, Rational, (%), numerator, denominator, approxRational ) where
+
+infixl 7  %
+
+ratPrec = 7 :: Int
+
+data  (Integral a)      => Ratio a = !a :% !a  deriving (Eq)
+type  Rational          =  Ratio Integer
+
+(%)                     :: (Integral a) => a -> a -> Ratio a
+numerator, denominator  :: (Integral a) => Ratio a -> a
+approxRational          :: (RealFrac a) => a -> a -> Rational
+
+
+-- "reduce" is a subsidiary function used only in this module.
+-- It normalises a ratio by dividing both numerator
+-- and denominator by their greatest common divisor.
+--
+-- E.g., 12 `reduce` 8    ==  3 :%   2
+--       12 `reduce` (-8) ==  3 :% (-2)
+
+reduce _ 0              =  error "Ratio.% : zero denominator"
+reduce x y              =  (x `quot` d) :% (y `quot` d)
+                           where d = gcd x y
+
+x % y                   =  reduce (x * signum y) (abs y)
+
+numerator (x :% _)      =  x
+
+denominator (_ :% y)    =  y
+
+
+instance  (Integral a)  => Ord (Ratio a)  where
+    (x:%y) <= (x':%y')  =  x * y' <= x' * y
+    (x:%y) <  (x':%y')  =  x * y' <  x' * y
+
+instance  (Integral a)  => Num (Ratio a)  where
+    (x:%y) + (x':%y')   =  reduce (x*y' + x'*y) (y*y')
+    (x:%y) * (x':%y')   =  reduce (x * x') (y * y')
+    negate (x:%y)       =  (-x) :% y
+    abs (x:%y)          =  abs x :% y
+    signum (x:%y)       =  signum x :% 1
+    fromInteger x       =  fromInteger x :% 1
+
+instance  (Integral a)  => Real (Ratio a)  where
+    toRational (x:%y)   =  toInteger x :% toInteger y
+
+instance  (Integral a)  => Fractional (Ratio a)  where
+    (x:%y) / (x':%y')   =  (x*y') % (y*x')
+    recip (x:%y)        =  y % x
+    fromRational (x:%y) =  fromInteger x :% fromInteger y
+
+instance  (Integral a)  => RealFrac (Ratio a)  where
+    properFraction (x:%y) = (fromIntegral q, r:%y)
+                            where (q,r) = quotRem x y
+
+instance  (Integral a)  => Enum (Ratio a)  where
+    succ x           =  x+1
+    pred x           =  x-1
+    toEnum           =  fromIntegral
+    fromEnum         =  fromInteger . truncate -- May overflow
+    enumFrom         =  numericEnumFrom                -- These numericEnumXXX functions
+    enumFromThen     =  numericEnumFromThen    -- are as defined in Prelude.hs
+    enumFromTo       =  numericEnumFromTo      -- but not exported from it!
+    enumFromThenTo   =  numericEnumFromThenTo
+
+instance  (Read a, Integral a)  => Read (Ratio a)  where
+    readsPrec p  =  readParen (p > ratPrec)
+                              (\r -> [(x%y,u) | (x,s)   <- readsPrec (ratPrec+1) r,
+                                                ("%",t) <- lex s,
+                                                (y,u)   <- readsPrec (ratPrec+1) t ])
+
+instance  (Integral a)  => Show (Ratio a)  where
+    showsPrec p (x:%y)  =  showParen (p > ratPrec)
+                               (showsPrec (ratPrec+1) x . 
+                               showString " % " . 
+                               showsPrec (ratPrec+1) y)
+
+
+
+approxRational x eps    =  simplest (x-eps) (x+eps)
+        where simplest x y | y < x      =  simplest y x
+                           | x == y     =  xr
+                           | x > 0      =  simplest' n d n' d'
+                           | y < 0      =  - simplest' (-n') d' (-n) d
+                           | otherwise  =  0 :% 1
+                                        where xr@(n:%d) = toRational x
+                                              (n':%d')  = toRational y
+
+              simplest' n d n' d'       -- assumes 0 < n%d < n'%d'
+                        | r == 0     =  q :% 1
+                        | q /= q'    =  (q+1) :% 1
+                        | otherwise  =  (q*n''+d'') :% n''
+                                     where (q,r)      =  quotRem n d
+                                           (q',r')    =  quotRem n' d'
+                                           (n'':%d'') =  simplest' d' r' d r
diff --git a/report/lib-code/Time.hs b/report/lib-code/Time.hs
new file mode 100644 (file)
index 0000000..93f0c56
--- /dev/null
@@ -0,0 +1,135 @@
+module Time (
+        ClockTime, 
+        Month(January,February,March,April,May,June,
+              July,August,September,October,November,December),
+        Day(Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday),
+       CalendarTime(CalendarTime, ctYear, ctMonth, ctDay, ctHour, ctMin,
+                    ctPicosec, ctWDay, ctYDay, ctTZName, ctTZ, ctIsDST),
+       TimeDiff(TimeDiff, tdYear, tdMonth, tdDay, 
+                tdHour, tdMin, tdSec, tdPicosec),
+        getClockTime, addToClockTime, diffClockTimes,
+        toCalendarTime, toUTCTime, toClockTime,
+        calendarTimeToString, formatCalendarTime ) where
+
+import Ix(Ix)
+import Locale(TimeLocale(..),defaultTimeLocale)
+import Char ( intToDigit )
+
+data ClockTime = ...                    -- Implementation-dependent
+instance Ord  ClockTime where ...
+instance Eq   ClockTime where ...
+
+data Month =  January   | February | March    | April
+           |  May       | June     | July     | August
+           |  September | October  | November | December
+           deriving (Eq, Ord, Enum, Bounded, Ix, Read, Show)
+
+data Day   =  Sunday | Monday  | Tuesday  | Wednesday | Thursday 
+           |  Friday | Saturday
+           deriving (Eq, Ord, Enum, Bounded, Ix, Read, Show)
+
+data CalendarTime = CalendarTime {
+                ctYear                          :: Int,
+                ctMonth                         :: Month,
+                ctDay, ctHour, ctMin, ctSec     :: Int,
+                ctPicosec                       :: Integer,
+                ctWDay                          :: Day,
+                ctYDay                          :: Int,
+                ctTZName                        :: String,
+                ctTZ                            :: Int,
+                ctIsDST                         :: Bool
+        } deriving (Eq, Ord, Read, Show)
+
+data TimeDiff = TimeDiff {
+                tdYear, tdMonth, tdDay, tdHour, tdMin, tdSec :: Int,
+                tdPicosec                                    :: Integer
+        } deriving (Eq, Ord, Read, Show)
+
+
+getClockTime            :: IO ClockTime
+getClockTime            = ...           -- Implementation-dependent
+
+addToClockTime          :: TimeDiff     -> ClockTime -> ClockTime
+addToClockTime td ct    =  ...          -- Implementation-dependent
+
+diffClockTimes          :: ClockTime    -> ClockTime -> TimeDiff
+diffClockTimes ct1 ct2  =  ...          -- Implementation-dependent
+
+toCalendarTime          :: ClockTime    -> IO CalendarTime
+toCalendarTime ct       =  ...          -- Implementation-dependent
+
+toUTCTime               :: ClockTime    -> CalendarTime
+toUTCTime ct            =  ...          -- Implementation-dependent
+
+toClockTime             :: CalendarTime -> ClockTime
+toClockTime cal         =  ...          -- Implementation-dependent
+
+calendarTimeToString    :: CalendarTime -> String
+calendarTimeToString    =  formatCalendarTime defaultTimeLocale "%c"
+
+formatCalendarTime :: TimeLocale -> String -> CalendarTime -> String
+formatCalendarTime l fmt ct@(CalendarTime year mon day hour min sec sdec 
+                                           wday yday tzname _ _) =
+        doFmt fmt
+  where doFmt ('%':c:cs) = decode c ++ doFmt cs
+        doFmt (c:cs) = c : doFmt cs
+        doFmt "" = ""
+
+        to12 :: Int -> Int
+        to12 h = let h' = h `mod` 12 in if h' == 0 then 12 else h'
+
+        decode 'A' = fst (wDays l  !! fromEnum wday)
+        decode 'a' = snd (wDays l  !! fromEnum wday)
+        decode 'B' = fst (months l !! fromEnum mon)
+        decode 'b' = snd (months l !! fromEnum mon)
+        decode 'h' = snd (months l !! fromEnum mon)
+        decode 'C' = show2 (year `quot` 100)
+        decode 'c' = doFmt (dateTimeFmt l)
+        decode 'D' = doFmt "%m/%d/%y"
+        decode 'd' = show2 day
+        decode 'e' = show2' day
+        decode 'H' = show2 hour
+        decode 'I' = show2 (to12 hour)
+        decode 'j' = show3 yday
+        decode 'k' = show2' hour
+        decode 'l' = show2' (to12 hour)
+        decode 'M' = show2 min
+        decode 'm' = show2 (fromEnum mon+1)
+        decode 'n' = "\n"
+        decode 'p' = (if hour < 12 then fst else snd) (amPm l)
+        decode 'R' = doFmt "%H:%M"
+        decode 'r' = doFmt (time12Fmt l)
+        decode 'T' = doFmt "%H:%M:%S"
+        decode 't' = "\t"
+        decode 'S' = show2 sec
+        decode 's' = ...                -- Implementation-dependent
+        decode 'U' = show2 ((yday + 7 - fromEnum wday) `div` 7)
+        decode 'u' = show (let n = fromEnum wday in 
+                           if n == 0 then 7 else n)
+        decode 'V' = 
+            let (week, days) = 
+                   (yday + 7 - if fromEnum wday > 0 then 
+                               fromEnum wday - 1 else 6) `divMod` 7
+            in  show2 (if days >= 4 then
+                          week+1 
+                       else if week == 0 then 53 else week)
+
+        decode 'W' = 
+            show2 ((yday + 7 - if fromEnum wday > 0 then 
+                               fromEnum wday - 1 else 6) `div` 7)
+        decode 'w' = show (fromEnum wday)
+        decode 'X' = doFmt (timeFmt l)
+        decode 'x' = doFmt (dateFmt l)
+        decode 'Y' = show year
+        decode 'y' = show2 (year `rem` 100)
+        decode 'Z' = tzname
+        decode '%' = "%"
+        decode c   = [c]
+
+show2, show2', show3 :: Int -> String
+show2 x = [intToDigit (x `quot` 10), intToDigit (x `rem` 10)]
+
+show2' x = if x < 10 then [ ' ', intToDigit x] else show2 x
+
+show3 x = intToDigit (x `quot` 100) : show2 (x `rem` 100)
+
diff --git a/report/lib-hdrs/Array.hs b/report/lib-hdrs/Array.hs
new file mode 100644 (file)
index 0000000..2bb99d0
--- /dev/null
@@ -0,0 +1,32 @@
+module  Array ( 
+        module Ix,  -- export all of Ix for convenience
+        Array, array, listArray, (!), bounds, indices, elems, assocs, 
+        accumArray, (//), accum, ixmap ) where
+
+import Ix
+
+infixl 9  !, //
+
+data  (Ix a)    => Array a b = ...     -- Abstract
+
+array           :: (Ix a) => (a,a) -> [(a,b)] -> Array a b
+listArray       :: (Ix a) => (a,a) -> [b] -> Array a b
+(!)             :: (Ix a) => Array a b -> a -> b
+bounds          :: (Ix a) => Array a b -> (a,a)
+indices         :: (Ix a) => Array a b -> [a]
+elems           :: (Ix a) => Array a b -> [b]
+assocs          :: (Ix a) => Array a b -> [(a,b)]
+accumArray      :: (Ix a) => (b -> c -> b) -> b -> (a,a) -> [(a,c)]
+                             -> Array a b
+(//)            :: (Ix a) => Array a b -> [(a,b)] -> Array a b
+accum           :: (Ix a) => (b -> c -> b) -> Array a b -> [(a,c)]
+                             -> Array a b
+ixmap           :: (Ix a, Ix b) => (a,a) -> (a -> b) -> Array b c
+                             -> Array a c
+
+instance                            Functor (Array a) where ...
+instance  (Ix a, Eq b)           => Eq   (Array a b)  where ...
+instance  (Ix a, Ord b)          => Ord  (Array a b)  where ...
+instance  (Ix a, Show a, Show b) => Show (Array a b)  where ...
+instance  (Ix a, Read a, Read b) => Read (Array a b)  where ...
+
diff --git a/report/lib-hdrs/CPUTime.hs b/report/lib-hdrs/CPUTime.hs
new file mode 100644 (file)
index 0000000..f03437a
--- /dev/null
@@ -0,0 +1,4 @@
+module CPUTime ( getCPUTime, cpuTimePrecision ) where
+
+getCPUTime        :: IO Integer
+cpuTimePrecision  :: Integer
diff --git a/report/lib-hdrs/Char.hs b/report/lib-hdrs/Char.hs
new file mode 100644 (file)
index 0000000..3722821
--- /dev/null
@@ -0,0 +1,26 @@
+module Char ( 
+    isAscii, isLatin1, isControl, isPrint, isSpace, isUpper, isLower, 
+    isAlpha, isDigit, isOctDigit, isHexDigit, isAlphaNum, 
+    digitToInt, intToDigit,
+    toUpper, toLower,
+    ord, chr,
+    readLitChar, showLitChar, lexLitChar,
+
+       -- ...and what the Prelude exports
+    Char, String
+    ) where
+
+isAscii, isLatin1, isControl, isPrint, isSpace, isUpper, isLower, 
+ isAlpha, isDigit, isOctDigit, isHexDigit, isAlphaNum :: Char -> Bool
+
+toUpper, toLower        :: Char -> Char
+
+digitToInt :: Char -> Int
+intToDigit :: Int -> Char
+
+ord        :: Char -> Int
+chr        :: Int  -> Char
+
+lexLitChar  :: ReadS String
+readLitChar :: ReadS Char
+showLitChar :: Char -> ShowS
diff --git a/report/lib-hdrs/Complex.hs b/report/lib-hdrs/Complex.hs
new file mode 100644 (file)
index 0000000..d78b78a
--- /dev/null
@@ -0,0 +1,21 @@
+module  Complex ( 
+    Complex((:+)), realPart, imagPart, conjugate, 
+    mkPolar, cis, polar, magnitude, phase ) where
+
+infix  6  :+
+
+data  (RealFloat a)     => Complex a = !a :+ !a
+
+realPart, imagPart      :: (RealFloat a) => Complex a -> a
+conjugate              :: (RealFloat a) => Complex a -> Complex a
+mkPolar                        :: (RealFloat a) => a -> a -> Complex a
+cis                    :: (RealFloat a) => a -> Complex a
+polar                  :: (RealFloat a) => Complex a -> (a,a)
+magnitude, phase        :: (RealFloat a) => Complex a -> a
+
+instance  (RealFloat a) => Eq         (Complex a)  where ...
+instance  (RealFloat a) => Read       (Complex a)  where ...
+instance  (RealFloat a) => Show       (Complex a)  where ...
+instance  (RealFloat a) => Num        (Complex a)  where ...
+instance  (RealFloat a) => Fractional (Complex a)  where ...
+instance  (RealFloat a) => Floating   (Complex a)  where ...
diff --git a/report/lib-hdrs/Directory.hs b/report/lib-hdrs/Directory.hs
new file mode 100644 (file)
index 0000000..e8315a3
--- /dev/null
@@ -0,0 +1,41 @@
+module Directory ( 
+    Permissions( Permissions, readable, writable, executable, searchable ), 
+    createDirectory, removeDirectory, removeFile, 
+    renameDirectory, renameFile, getDirectoryContents,
+    getCurrentDirectory, setCurrentDirectory,
+    doesFileExist, doesDirectoryExist,
+    getPermissions, setPermissions,
+    getModificationTime ) where
+
+import Time ( ClockTime )
+
+data Permissions = Permissions {
+                       readable,   writable,
+                       executable, searchable :: Bool
+                  }
+
+instance Eq   Permissions where ...
+instance Ord  Permissions where ...
+instance Read Permissions where ...
+instance Show Permissions where ...
+
+
+
+createDirectory        :: FilePath -> IO ()
+removeDirectory        :: FilePath -> IO ()
+removeFile             :: FilePath -> IO ()
+renameDirectory        :: FilePath -> FilePath -> IO ()
+renameFile             :: FilePath -> FilePath -> IO ()
+
+getDirectoryContents   :: FilePath -> IO [FilePath]
+getCurrentDirectory    :: IO FilePath
+setCurrentDirectory    :: FilePath -> IO ()
+
+doesFileExist          :: FilePath -> IO Bool
+doesDirectoryExist     :: FilePath -> IO Bool
+
+getPermissions         :: FilePath -> IO Permissions
+setPermissions         :: FilePath -> Permissions -> IO ()
+
+getModificationTime    :: FilePath -> IO ClockTime
+
diff --git a/report/lib-hdrs/IO.hs b/report/lib-hdrs/IO.hs
new file mode 100644 (file)
index 0000000..2e2b1d8
--- /dev/null
@@ -0,0 +1,47 @@
+module IO (
+    Handle, HandlePosn,
+    IOMode(ReadMode,WriteMode,AppendMode,ReadWriteMode),
+    BufferMode(NoBuffering,LineBuffering,BlockBuffering),
+    SeekMode(AbsoluteSeek,RelativeSeek,SeekFromEnd),
+    stdin, stdout, stderr, 
+    openFile, hClose, hFileSize, hIsEOF, isEOF,
+    hSetBuffering, hGetBuffering, hFlush, 
+    hGetPosn, hSetPosn, hSeek, 
+    hWaitForInput, hReady, hGetChar, hGetLine, hLookAhead, hGetContents, 
+    hPutChar, hPutStr, hPutStrLn, hPrint,
+    hIsOpen, hIsClosed, hIsReadable, hIsWritable, hIsSeekable,
+    isAlreadyExistsError, isDoesNotExistError, isAlreadyInUseError, 
+    isFullError, isEOFError,
+    isIllegalOperation, isPermissionError, isUserError, 
+    ioeGetErrorString, ioeGetHandle, ioeGetFileName,
+    try, bracket, bracket_,
+
+    -- ...and what the Prelude exports
+    IO, FilePath, IOError, ioError, userError, catch, interact,
+    putChar, putStr, putStrLn, print, getChar, getLine, getContents,
+    readFile, writeFile, appendFile, readIO, readLn
+    ) where
+
+import Ix(Ix)
+
+data Handle = ...                      -- implementation-dependent
+instance Eq Handle where ...
+instance Show Handle where ..           -- implementation-dependent
+
+data HandlePosn = ...                  -- implementation-dependent
+instance Eq HandlePosn where ...
+instance Show HandlePosn where ---      -- implementation-dependent
+
+
+data IOMode      =  ReadMode | WriteMode | AppendMode | ReadWriteMode
+                    deriving (Eq, Ord, Ix, Bounded, Enum, Read, Show)
+data BufferMode  =  NoBuffering | LineBuffering 
+                 |  BlockBuffering (Maybe Int)
+                    deriving (Eq, Ord, Read, Show)
+data SeekMode    =  AbsoluteSeek | RelativeSeek | SeekFromEnd
+                    deriving (Eq, Ord, Ix, Bounded, Enum, Read, Show)
+
+stdin, stdout, stderr :: Handle
+
+openFile              :: FilePath -> IOMode -> IO Handle
+hClose                :: Handle -> IO ()
diff --git a/report/lib-hdrs/IO1.hs b/report/lib-hdrs/IO1.hs
new file mode 100644 (file)
index 0000000..413affd
--- /dev/null
@@ -0,0 +1,46 @@
+hFileSize             :: Handle -> IO Integer
+hIsEOF                :: Handle -> IO Bool
+isEOF                 :: IO Bool
+isEOF                 =  hIsEOF stdin
+
+hSetBuffering         :: Handle  -> BufferMode -> IO ()
+hGetBuffering         :: Handle  -> IO BufferMode
+hFlush                :: Handle -> IO () 
+hGetPosn              :: Handle -> IO HandlePosn
+hSetPosn              :: HandlePosn -> IO () 
+hSeek                 :: Handle -> SeekMode -> Integer -> IO () 
+
+hWaitForInput        :: Handle -> Int -> IO Bool
+hReady                :: Handle -> IO Bool 
+hReady h             =  hWaitForInput h 0
+hGetChar              :: Handle -> IO Char
+hGetLine              :: Handle -> IO String
+hLookAhead            :: Handle -> IO Char
+hGetContents          :: Handle -> IO String
+hPutChar              :: Handle -> Char -> IO ()
+hPutStr               :: Handle -> String -> IO ()
+hPutStrLn             :: Handle -> String -> IO ()
+hPrint                :: Show a => Handle -> a -> IO ()
+
+hIsOpen               :: Handle -> IO Bool
+hIsClosed             :: Handle -> IO Bool
+hIsReadable           :: Handle -> IO Bool
+hIsWritable           :: Handle -> IO Bool
+hIsSeekable           :: Handle -> IO Bool
+
+isAlreadyExistsError  :: IOError -> Bool
+isDoesNotExistError   :: IOError -> Bool
+isAlreadyInUseError   :: IOError -> Bool
+isFullError           :: IOError -> Bool
+isEOFError            :: IOError -> Bool
+isIllegalOperation    :: IOError -> Bool
+isPermissionError     :: IOError -> Bool
+isUserError           :: IOError -> Bool
+
+ioeGetErrorString     :: IOError -> String
+ioeGetHandle          :: IOError -> Maybe Handle
+ioeGetFileName        :: IOError -> Maybe FilePath
+
+try                   :: IO a -> IO (Either IOError a)
+bracket               :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
+bracket_              :: IO a -> (a -> IO b) -> IO c -> IO c
diff --git a/report/lib-hdrs/Ix.hs b/report/lib-hdrs/Ix.hs
new file mode 100644 (file)
index 0000000..ac5199d
--- /dev/null
@@ -0,0 +1,15 @@
+module Ix ( Ix(range, index, inRange, rangeSize) ) where
+
+class  Ord a => Ix a  where
+    range       :: (a,a) -> [a]
+    index       :: (a,a) -> a -> Int
+    inRange     :: (a,a) -> a -> Bool
+    rangeSize   :: (a,a) -> Int
+
+instance                   Ix Char      where ...
+instance                   Ix Int       where ...
+instance                   Ix Integer   where ...
+instance  (Ix a, Ix b)  => Ix (a,b)     where ...
+-- et cetera
+instance                   Ix Bool      where ...
+instance                   Ix Ordering  where ...
diff --git a/report/lib-hdrs/List.hs b/report/lib-hdrs/List.hs
new file mode 100644 (file)
index 0000000..df18dd3
--- /dev/null
@@ -0,0 +1,44 @@
+module List ( 
+    elemIndex, elemIndices,
+    find, findIndex, findIndices,
+    nub, nubBy, delete, deleteBy, (\\), deleteFirstsBy,
+    union, unionBy, intersect, intersectBy,
+    intersperse, transpose, partition, group, groupBy,
+    inits, tails, isPrefixOf, isSuffixOf,
+    mapAccumL, mapAccumR,
+    sort, sortBy, insert, insertBy, maximumBy, minimumBy,
+    genericLength, genericTake, genericDrop,
+    genericSplitAt, genericIndex, genericReplicate,
+    zip4, zip5, zip6, zip7,
+    zipWith4, zipWith5, zipWith6, zipWith7,
+    unzip4, unzip5, unzip6, unzip7, unfoldr,
+
+    -- ...and what the Prelude exports
+    -- []((:), []),    -- This is built-in syntax
+    map, (++), concat, filter,
+    head, last, tail, init, null, length, (!!),
+    foldl, foldl1, scanl, scanl1, foldr, foldr1, scanr, scanr1,
+    iterate, repeat, replicate, cycle,
+    take, drop, splitAt, takeWhile, dropWhile, span, break,
+    lines, words, unlines, unwords, reverse, and, or,
+    any, all, elem, notElem, lookup,
+    sum, product, maximum, minimum, concatMap, 
+    zip, zip3, zipWith, zipWith3, unzip, unzip3
+    ) where
+
+infix 5 \\
+
+elemIndex           :: Eq a => a -> [a] -> Maybe Int
+elemIndices         :: Eq a => a -> [a] -> [Int]
+find                :: (a -> Bool) -> [a] -> Maybe a
+findIndex           :: (a -> Bool) -> [a] -> Maybe Int
+findIndices         :: (a -> Bool) -> [a] -> [Int]
+nub                 :: Eq a => [a] -> [a]
+nubBy               :: (a -> a -> Bool) -> [a] -> [a]
+delete              :: Eq a => a -> [a] -> [a]
+deleteBy            :: (a -> a -> Bool) -> a -> [a] -> [a]
+(\\)                :: Eq a => [a] -> [a] -> [a]
+deleteFirstsBy      :: (a -> a -> Bool) -> [a] -> [a] -> [a]
+union               :: Eq a => [a] -> [a] -> [a]
+unionBy             :: (a -> a -> Bool) -> [a] -> [a] -> [a]
+
diff --git a/report/lib-hdrs/List1.hs b/report/lib-hdrs/List1.hs
new file mode 100644 (file)
index 0000000..897d28f
--- /dev/null
@@ -0,0 +1,44 @@
+intersect        :: Eq a => [a] -> [a] -> [a]
+intersectBy      :: (a -> a -> Bool) -> [a] -> [a] -> [a]
+intersperse      :: a -> [a] -> [a]
+transpose        :: [[a]] -> [[a]]
+partition        :: (a -> Bool) -> [a] -> ([a],[a])
+group            :: Eq a => [a] -> [[a]]
+groupBy          :: (a -> a -> Bool) -> [a] -> [[a]]
+inits            :: [a] -> [[a]] 
+tails            :: [a] -> [[a]] 
+isPrefixOf       :: Eq a => [a] -> [a] -> Bool
+isSuffixOf       :: Eq a => [a] -> [a] -> Bool
+mapAccumL        :: (a -> b -> (a, c)) -> a -> [b] -> (a, [c])
+mapAccumR        :: (a -> b -> (a, c)) -> a -> [b] -> (a, [c])
+unfoldr                 :: (b -> Maybe (a,b)) -> b -> [a]
+sort             :: Ord a => [a] -> [a]
+sortBy           :: (a -> a -> Ordering) -> [a] -> [a]
+insert          :: Ord a => a -> [a] -> [a]
+insertBy         :: (a -> a -> Ordering) -> a -> [a] -> [a]
+maximumBy        :: (a -> a -> Ordering) -> [a] -> a
+minimumBy        :: (a -> a -> Ordering) -> [a] -> a
+genericLength    :: Integral a => [b] -> a
+genericTake     :: Integral a => a -> [b] -> [b]
+genericDrop     :: Integral a => a -> [b] -> [b]
+genericSplitAt  :: Integral a => a -> [b] -> ([b],[b])
+genericIndex    :: Integral a => [b] -> a -> b
+genericReplicate :: Integral a => a -> b -> [b]
+
+zip4             :: [a] -> [b] -> [c] -> [d] -> [(a,b,c,d)]
+zip5             :: [a] -> [b] -> [c] -> [d] -> [e] -> [(a,b,c,d,e)]
+zip6             :: [a] -> [b] -> [c] -> [d] -> [e] -> [f] 
+                       -> [(a,b,c,d,e,f)]
+zip7             :: [a] -> [b] -> [c] -> [d] -> [e] -> [f] -> [g]
+                       -> [(a,b,c,d,e,f,g)]
+zipWith4         :: (a->b->c->d->e) -> [a]->[b]->[c]->[d]->[e]
+zipWith5         :: (a->b->c->d->e->f) -> 
+                    [a]->[b]->[c]->[d]->[e]->[f]
+zipWith6         :: (a->b->c->d->e->f->g) ->
+                    [a]->[b]->[c]->[d]->[e]->[f]->[g]
+zipWith7         :: (a->b->c->d->e->f->g->h) ->
+                    [a]->[b]->[c]->[d]->[e]->[f]->[g]->[h]
+unzip4           :: [(a,b,c,d)] -> ([a],[b],[c],[d])
+unzip5           :: [(a,b,c,d,e)] -> ([a],[b],[c],[d],[e])
+unzip6           :: [(a,b,c,d,e,f)] -> ([a],[b],[c],[d],[e],[f])
+unzip7           :: [(a,b,c,d,e,f,g)] -> ([a],[b],[c],[d],[e],[f],[g])
diff --git a/report/lib-hdrs/Locale.hs b/report/lib-hdrs/Locale.hs
new file mode 100644 (file)
index 0000000..a9a57d1
--- /dev/null
@@ -0,0 +1,11 @@
+module Locale(TimeLocale(..), defaultTimeLocale) where
+
+data TimeLocale = TimeLocale {
+        wDays  :: [(String, String)],   -- full and abbreviated week days
+        months :: [(String, String)],   -- full and abbreviated months
+        amPm   :: (String, String),     -- AM/PM symbols
+        dateTimeFmt, dateFmt,           -- formatting strings
+          timeFmt, time12Fmt :: String     
+        } deriving (Eq, Ord, Show)
+
+defaultTimeLocale :: TimeLocale 
diff --git a/report/lib-hdrs/Maybe.hs b/report/lib-hdrs/Maybe.hs
new file mode 100644 (file)
index 0000000..e536efa
--- /dev/null
@@ -0,0 +1,17 @@
+module Maybe(
+    isJust, isNothing,
+    fromJust, fromMaybe, listToMaybe, maybeToList,
+    catMaybes, mapMaybe,
+
+    -- ...and what the Prelude exports
+    Maybe(Nothing, Just),
+    maybe
+  ) where
+
+isJust, isNothing    :: Maybe a -> Bool
+fromJust             :: Maybe a -> a
+fromMaybe            :: a -> Maybe a -> a
+listToMaybe          :: [a] -> Maybe a
+maybeToList          :: Maybe a -> [a]
+catMaybes            :: [Maybe a] -> [a]
+mapMaybe             :: (a -> Maybe b) -> [a] -> [b]
diff --git a/report/lib-hdrs/Monad.hs b/report/lib-hdrs/Monad.hs
new file mode 100644 (file)
index 0000000..561e29f
--- /dev/null
@@ -0,0 +1,40 @@
+module Monad (
+    MonadPlus(mzero, mplus),
+    join, guard, when, unless, ap,
+    msum,
+    filterM, mapAndUnzipM, zipWithM, zipWithM_, foldM, 
+    liftM, liftM2, liftM3, liftM4, liftM5,
+
+    -- ...and what the Prelude exports
+    Monad((>>=), (>>), return, fail),
+    Functor(fmap),
+    mapM, mapM_, sequence, sequence_, (=<<), 
+    ) where
+
+class  Monad m => MonadPlus m  where
+    mzero  :: m a
+    mplus  :: m a -> m a -> m a
+
+join             :: Monad m => m (m a) -> m a
+guard            :: MonadPlus m => Bool -> m ()
+when             :: Monad m => Bool -> m () -> m ()
+unless           :: Monad m => Bool -> m () -> m ()
+ap              :: Monad m => m (a -> b) -> m a -> m b
+
+mapAndUnzipM     :: Monad m => (a -> m (b,c)) -> [a] -> m ([b], [c])
+zipWithM         :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m [c]
+zipWithM_        :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m ()
+foldM            :: Monad m => (a -> b -> m a) -> a -> [b] -> m a
+filterM                 :: Monad m => (a -> m Bool) -> [a] -> m [a]
+
+msum            :: MonadPlus m => [m a] -> m a
+
+liftM            :: Monad m => (a -> b) -> (m a -> m b)
+liftM2           :: Monad m => (a -> b -> c) -> (m a -> m b -> m c)
+liftM3           :: Monad m => (a -> b -> c -> d) ->
+                               (m a -> m b -> m c -> m d)
+liftM4           :: Monad m => (a -> b -> c -> d -> e) ->
+                               (m a -> m b -> m c -> m d -> m e)
+liftM5           :: Monad m => (a -> b -> c -> d -> e -> f) ->
+                               (m a -> m b -> m c -> m d -> m e -> m f)
+
diff --git a/report/lib-hdrs/Numeric.hs b/report/lib-hdrs/Numeric.hs
new file mode 100644 (file)
index 0000000..04e6710
--- /dev/null
@@ -0,0 +1,33 @@
+module Numeric(fromRat,
+               showSigned, showIntAtBase,
+               showInt, showOct, showHex,
+               readSigned, readInt,
+               readDec, readOct, readHex, 
+               floatToDigits,
+               showEFloat, showFFloat, showGFloat, showFloat, 
+               readFloat, lexDigits) where
+
+fromRat        :: (RealFloat a) => Rational -> a
+
+showSigned     :: (Real a) => (a -> ShowS) -> Int -> a -> ShowS
+showIntAtBase  :: Integral a => a -> (Int -> Char) -> a -> ShowS
+showInt        :: Integral a => a -> ShowS
+showOct        :: Integral a => a -> ShowS
+showHex        :: Integral a => a -> ShowS
+
+readSigned     :: (Real a) => ReadS a -> ReadS a
+readInt        :: (Integral a) =>
+                    a -> (Char -> Bool) -> (Char -> Int) -> ReadS a
+readDec        :: (Integral a) => ReadS a
+readOct        :: (Integral a) => ReadS a
+readHex        :: (Integral a) => ReadS a
+
+showEFloat     :: (RealFloat a) => Maybe Int -> a -> ShowS
+showFFloat     :: (RealFloat a) => Maybe Int -> a -> ShowS
+showGFloat     :: (RealFloat a) => Maybe Int -> a -> ShowS
+showFloat      :: (RealFloat a) => a -> ShowS
+
+floatToDigits  :: (RealFloat a) => Integer -> a -> ([Int], Int)
+
+readFloat      :: (RealFrac a) => ReadS a
+lexDigits      :: ReadS String 
diff --git a/report/lib-hdrs/Random.hs b/report/lib-hdrs/Random.hs
new file mode 100644 (file)
index 0000000..76f587a
--- /dev/null
@@ -0,0 +1,50 @@
+module Random (
+       RandomGen(next, split, genRange),
+       StdGen, mkStdGen,
+       Random( random,   randomR, 
+               randoms,  randomRs,
+               randomIO, randomRIO ),
+       getStdRandom, getStdGen, setStdGen, newStdGen
+  ) where
+       
+---------------- The RandomGen class ------------------------
+
+class RandomGen g where
+  genRange :: g -> (Int, Int)
+  next     :: g -> (Int, g)
+  split    :: g -> (g, g)
+
+---------------- A standard instance of RandomGen -----------
+data StdGen = ...      -- Abstract
+
+instance RandomGen StdGen where ...
+instance Read     StdGen where ...
+instance Show     StdGen where ...
+
+mkStdGen :: Int -> StdGen
+
+---------------- The Random class ---------------------------
+class Random a where
+   randomR :: RandomGen g => (a, a) -> g -> (a, g)
+   random  :: RandomGen g => g -> (a, g)
+
+   randomRs :: RandomGen g => (a, a) -> g -> [a]
+   randoms  :: RandomGen g => g -> [a]
+
+   randomRIO :: (a,a) -> IO a
+   randomIO  :: IO a
+
+instance Random Int     where ...
+instance Random Integer where ...
+instance Random Float   where ...
+instance Random Double  where ...
+instance Random Bool    where ...
+instance Random Char    where ...
+
+---------------- The global random generator ----------------
+newStdGen    :: IO StdGen
+setStdGen    :: StdGen -> IO ()
+getStdGen    :: IO StdGen      
+getStdRandom :: (StdGen -> (a, StdGen)) -> IO a
+
+
diff --git a/report/lib-hdrs/Ratio.hs b/report/lib-hdrs/Ratio.hs
new file mode 100644 (file)
index 0000000..13755cf
--- /dev/null
@@ -0,0 +1,19 @@
+module Ratio (
+    Ratio, Rational, (%), numerator, denominator, approxRational ) where
+
+infixl 7  %
+data  (Integral a)     => Ratio a = ...
+type  Rational         =  Ratio Integer
+(%)                    :: (Integral a) => a -> a -> Ratio a
+numerator, denominator :: (Integral a) => Ratio a -> a
+approxRational         :: (RealFrac a) => a -> a -> Rational
+instance  (Integral a)  => Eq         (Ratio a)  where ...
+instance  (Integral a) => Ord        (Ratio a)  where ...
+instance  (Integral a) => Num        (Ratio a)  where ...
+instance  (Integral a) => Real       (Ratio a)  where ...
+instance  (Integral a) => Fractional (Ratio a)  where ...
+instance  (Integral a) => RealFrac   (Ratio a)  where ...
+instance  (Integral a) => Enum       (Ratio a)  where ...
+instance  (Read a,Integral a) => Read (Ratio a)  where ...
+instance  (Integral a)  => Show       (Ratio a)  where ...
+
diff --git a/report/lib-hdrs/System.hs b/report/lib-hdrs/System.hs
new file mode 100644 (file)
index 0000000..e534519
--- /dev/null
@@ -0,0 +1,14 @@
+module System ( 
+    ExitCode(ExitSuccess,ExitFailure),
+    getArgs, getProgName, getEnv, system, exitWith, exitFailure
+  ) where
+
+data ExitCode = ExitSuccess | ExitFailure Int 
+                deriving (Eq, Ord, Read, Show)
+
+getArgs                :: IO [String]
+getProgName            :: IO String
+getEnv                 :: String -> IO String
+system                 :: String -> IO ExitCode
+exitWith               :: ExitCode -> IO a
+exitFailure            :: IO a
diff --git a/report/lib-hdrs/Time.hs b/report/lib-hdrs/Time.hs
new file mode 100644 (file)
index 0000000..971c0a3
--- /dev/null
@@ -0,0 +1,44 @@
+module Time (
+       ClockTime, 
+       Month(January,February,March,April,May,June,
+             July,August,September,October,November,December),
+       Day(Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday),
+       CalendarTime(CalendarTime, ctYear, ctMonth, ctDay, ctHour, ctMin,
+                    ctPicosec, ctWDay, ctYDay, ctTZName, ctTZ, ctIsDST),
+       TimeDiff(TimeDiff, tdYear, tdMonth, tdDay, tdHour,
+                tdMin, tdSec, tdPicosec),
+       getClockTime, addToClockTime, diffClockTimes,
+        toCalendarTime, toUTCTime, toClockTime,
+        calendarTimeToString, formatCalendarTime ) where
+
+import Ix(Ix)
+
+data ClockTime = ...                   -- Implementation-dependent
+instance Ord  ClockTime where ...
+instance Eq   ClockTime where ...
+
+data Month =  January   | February | March    | April
+           |  May       | June     | July     | August
+           |  September | October  | November | December
+           deriving (Eq, Ord, Enum, Bounded, Ix, Read, Show)
+
+data Day   =  Sunday | Monday  | Tuesday  | Wednesday | Thursday 
+           |  Friday | Saturday
+           deriving (Eq, Ord, Enum, Bounded, Ix, Read, Show)
+
+data CalendarTime = CalendarTime {
+               ctYear                          :: Int,
+               ctMonth                         :: Month,
+               ctDay, ctHour, ctMin, ctSec     :: Int,
+               ctPicosec                       :: Integer,
+               ctWDay                          :: Day,
+               ctYDay                          :: Int,
+               ctTZName                        :: String,
+               ctTZ                            :: Int,
+               ctIsDST                         :: Bool
+       } deriving (Eq, Ord, Read, Show)
+
+data TimeDiff = TimeDiff {
+               tdYear, tdMonth, tdDay, tdHour, tdMin, tdSec :: Int,
+               tdPicosec                                    :: Integer
+       } deriving (Eq, Ord, Read, Show)
diff --git a/report/lib-hdrs/Time1.hs b/report/lib-hdrs/Time1.hs
new file mode 100644 (file)
index 0000000..1ce79d5
--- /dev/null
@@ -0,0 +1,11 @@
+-- Functions on times
+getClockTime         :: IO ClockTime
+                    
+addToClockTime       :: TimeDiff  -> ClockTime -> ClockTime
+diffClockTimes       :: ClockTime -> ClockTime -> TimeDiff
+                    
+toCalendarTime       :: ClockTime    -> IO CalendarTime
+toUTCTime            :: ClockTime    -> CalendarTime
+toClockTime          :: CalendarTime -> ClockTime
+calendarTimeToString :: CalendarTime -> String
+formatCalendarTime   :: TimeLocale -> String -> CalendarTime -> String
diff --git a/report/list.verb b/report/list.verb
new file mode 100644 (file)
index 0000000..df70db0
--- /dev/null
@@ -0,0 +1,273 @@
+%**<title>The Haskell 98 Library Report: List Utilities</title>
+%**~header
+\section{List Utilities}
+
+\outline{
+\inputHS{lib-hdrs/List}
+}
+\outline{
+\inputHS{lib-hdrs/List1}
+}
+
+This library defines some lesser-used operations over lists.
+
+\subsection{Indexing lists}
+
+\begin{itemize}
+\item @elemIndex val list@\indextt{elemIndex} returns the index of
+the first occurrence, if any, of @val@  
+in @list@ as @Just index@.  @Nothing@ is returned if @not (val `elem` list)@.
+
+\item @elemIndices val list@\indextt{elemIndices} returns an
+in-order list of indices, giving the occurrences of @val@ in @list@.
+
+\item  @find@\indextt{find} 
+returns the first element of a list that satisfies a predicate,
+or Nothing, if there is no such element.
+@findIndex@ returns the corresponding index.
+@findIndices@ returns a list of all such indices.
+\end{itemize}
+
+\subsection{``Set'' operations}
+
+There are a number of ``set'' operations defined over the @List@ type.
+@nub@ (meaning ``essence'') removes duplicates elements from a list.
+@delete@, @(\\)@, @union@ and @intersect@ (and their @By@ variants) 
+preserve the invariant their result
+does not contain duplicates, provided that their first argument
+contains no duplicates.
+
+\begin{itemize}
+\item 
+@nub@\indextt{nub} removes duplicate elements from a list. For example:
+\bprog
+@
+  nub [1,3,1,4,3,3] = [1,3,4]
+@
+\eprog
+\item
+@delete x@\indextt{delete} 
+removes the first occurrence of @x@ from its list argument,
+e.g.,  
+\bprog
+@
+  delete 'a' "banana" == "bnana"
+@
+\eprog
+
+\item
+@(\\)@\indextt{(\\)} is list 
+difference (non-associative).  In the result of @xs \\ ys@,
+the first occurrence of each element of @ys@ in turn (if any)
+has been removed from @xs@.  Thus, @(xs ++ ys) \\ xs == ys@.
+
+\item 
+@union@\indextt{union} is list union, e.g., 
+\bprog
+@
+  "dog" `union` "cow" == "dogcw"
+@
+\eprog
+
+\item
+@intersect@\indextt{intersect} is list intersection, e.g.,  
+\bprog
+@
+  [1,2,3,4] `intersect` [2,4,6,8] == [2,4]
+@
+\eprog
+\end{itemize}
+
+\subsection{List transformations}
+
+\begin{itemize}
+\item
+@intersperse sep@\indextt{intersperse} 
+inserts @sep@ between the elements of its list argument,
+e.g.,  
+\bprog
+@
+  intersperse ',' "abcde" == "a,b,c,d,e"
+@
+\eprog
+
+\item
+@transpose@\indextt{transpose} transposes the rows and columns of its argument,
+e.g., 
+\bprog
+@
+  transpose [[1,2,3],[4,5,6]] == [[1,4],[2,5],[3,6]]
+@
+\eprog
+
+\item
+@partition@\indextt{partition} 
+takes a predicate and a list and returns a pair of lists:
+those elements of the argument list that do and do not satisfy the
+predicate, respectively; i.e.,
+\bprog
+@
+  partition p xs == (filter p xs, filter (not . p) xs)
+@
+\eprog
+
+\item
+@sort@\indextt{sort}
+implement a stable sorting algorithm, here specified
+in terms of the @insertBy@ function, which inserts objects into a list
+according to the specified ordering relation.
+
+\item
+@insert@\indextt{insert}
+inserts a new element into an {\em ordered} list (arranged in increasing order).
+
+\item
+@group@\indextt{group} splits its list argument into a list of lists of equal, adjacent
+elements. For example
+\bprog
+@
+  group "Mississippi" == ["M","i","ss","i","ss","i","pp","i"]
+@
+\eprog
+
+\item
+@inits@\indextt{inits} returns the list of initial segments of its argument list, shortest first.
+\bprog
+@
+  inits "abc" == ["","a","ab","abc"]
+@
+\eprog
+
+\item
+@tails@\indextt{tails} 
+returns the list of all final segments of its argument list, longest first.
+\bprog
+@
+  tails "abc" == ["abc", "bc", "c",""]
+@
+
+\eprog
+\item
+@mapAccumL f s l@\indextt{mapAccumL} 
+applies @f@ to an accumulating ``state'' parameter @s@
+and to each element of @l@ in turn.
+
+\item
+@mapAccumR@\indextt{mapAccumR}
+is similar to @mapAccumL@ except that the list
+is processed from right-to-left rather than left-to-right.
+\end{itemize}
+
+\subsection{@unfoldr@}
+
+The @unfoldr@ function is a `dual' to @foldr@: while @foldr@ reduces a list
+to a summary value, @unfoldr@ builds a list from a seed value.  For 
+example:
+\bprog
+@
+  iterate f == unfoldr (\x -> Just (x, f x))
+@
+\eprog
+In some cases, @unfoldr@ can undo a @foldr@ operation:
+\bprog
+@
+  unfoldr f' (foldr f z xs) == xs
+@
+\eprog
+if the following holds:
+\bprog
+@
+  f' (f x y) = Just (x,y)
+  f' z       = Nothing
+@
+\eprog
+
+\subsection{Predicates}
+
+@isPrefixOf@ and @isSuffixOf@ check whether the first argument is a prefix (resp. suffix)
+of the second argument.
+
+
+\subsection{The ``@By@'' operations}
+
+By convention, overloaded functions have a non-overloaded
+counterpart whose name is suffixed with ``@By@''.  For example, the
+function @nub@ could be defined as follows:
+\bprog
+@
+  nub              :: (Eq a) => [a] -> [a]
+  nub []           =  []
+  nub (x:xs)       =  x : nub (filter (\y -> not (x == y)) xs)
+@
+\eprog
+However, the equality method may not be appropriate in all situations.
+The function:
+\bprog
+@
+  nubBy            :: (a -> a -> Bool) -> [a] -> [a]
+  nubBy eq []      =  []
+  nubBy eq (x:xs)  =  x : nubBy eq (filter (\y -> not (eq x y)) xs)
+@
+\eprog
+allows the programmer to supply their own equality test.
+When the ``@By@'' function replaces an @Eq@ context by a binary predicate,
+the predicate is assumed to define an equivalence; when the ``@By@''
+function replaces an @Ord@ context by a binary predicate, the
+predicate is assumed to define a total ordering.
+
+The ``@By@'' variants are as follows:
+@nubBy@, @deleteBy@, @deleteFirstsBy@ (the "@By@" variant of @\\@),
+@unionBy@, @intersectBy@, @groupBy@,
+@sortBy@, @insertBy@, @maximumBy@, @minimumBy@.  
+\indextt{nubBy} 
+\indextt{deleteBy} 
+\indextt{deleteFirstsBy} 
+\indextt{unionBy} 
+\indextt{intersectBy} 
+\indextt{groupBy} 
+\indextt{sortBy} 
+\indextt{insertBy} 
+\indextt{maximumBy} 
+\indextt{minimumBy} 
+
+The library does not
+provide @elemBy@, because @any (eq x)@ does the same job as @elemBy eq x@ would.
+A handful of overloaded functions (@elemIndex@, @elemIndices@, @isPrefixOf@, @isSuffixOf@)
+were not considered important enough to have ``@By@'' variants.
+
+% Several of the functions defined here are derivatives of, or
+% related to, Prelude functions.  These functions are
+% @elem@, @maximum@, @minimum@, @zip@, @zip3@, @zipWith@,
+% @zipWith3@, @unzip@, @unzip3@, 
+% [according to Keith] @take@, @drop@, @splitAt@, @index@, @replicate@.
+
+\subsection{The ``@generic@'' operations}
+
+The prefix ``@generic@'' indicates an overloaded function that is
+a generalised version of a @Prelude@ function.  For example,
+\bprog
+@
+  genericLength       :: Integral a => [b] -> a
+@ 
+\eprog
+is a generalised version of @length@.
+
+The ``@generic@'' operations are as follows:
+@genericLength@, @genericTake@, @genericDrop@,
+    @genericSplitAt@, @genericIndex@ (the generic version of @!!@), @genericReplicate@.
+
+
+\subsection{Further ``@zip@'' operations}
+
+The Prelude provides @zip@, @zip3@, @unzip@, @unzip3@, @zipWith@, and @zipWith3@.
+The List library provides these same three operations for 4, 5, 6, and 7 arguments.
+\indextt{zip4}
+\indextt{unzip4}
+\indextt{zipWith4}
+
+\clearpage
+\subsection{Library {\tt List}}
+\label{List}
+\inputHS{lib-code/List}
+
+%**~footer
index 71207fe..bf27a5d 100644 (file)
@@ -1,10 +1,9 @@
 %
-% $Header: /home/cvs/root/haskell-report/report/literate.verb,v 1.4 2001/12/21 16:00:25 simonpj Exp $
+% $Header: /home/cvs/root/haskell-report/report/literate.verb,v 1.5 2002/12/02 14:53:30 simonpj Exp $
 %
 %**<title>The Haskell 98 Report: Literate Comments</title>
-%*section C
 %**~header
-\section{Literate comments}
+\subsection{Literate comments}
 \label{literate}
 \index{literate comments}
 
diff --git a/report/locale.verb b/report/locale.verb
new file mode 100644 (file)
index 0000000..fc57962
--- /dev/null
@@ -0,0 +1,19 @@
+%**<title>The Haskell 98 Library Report: Locale</title>
+%**~header
+\section{Locale}
+\label{locale}
+\index{locale}
+
+\outline {
+\inputHS{lib-hdrs/Locale}
+}
+
+The @Locale@ library provides the ability to adapt to local
+conventions.  At present, it supports only time and date information
+as used by @calendarTimeToString@ from the @Time@ library.
+
+\clearpage
+\subsection{Library {\tt Locale}}
+\inputHS{lib-code/Locale}
+
+%**~footer
diff --git a/report/maybe.verb b/report/maybe.verb
new file mode 100644 (file)
index 0000000..93bdf8c
--- /dev/null
@@ -0,0 +1,30 @@
+%**<title>The Haskell 98 Library Report: Maybe Utilities</title>
+%**~header
+\section{Maybe Utilities}
+
+\outline{
+\inputHS{lib-hdrs/Maybe}
+}
+
+The type constructor @Maybe@ is defined in @Prelude@ as
+\bprog
+@
+data Maybe a = Nothing | Just a
+@
+\eprog
+The purpose of the @Maybe@ type is to provide a method of dealing with
+illegal or optional values without terminating the program, as would
+happen if @error@ were used, and without using @IOError@ from the @IO@
+monad, which would cause the expression to become monadic.  A correct
+result is encapsulated by wrapping it in @Just@; an incorrect result
+is returned as @Nothing@.
+
+Other operations on @Maybe@ are provided as part of the monadic
+classes in the Prelude.
+
+\clearpage
+\subsection{Library {\tt Maybe}}
+\label {Maybe}
+\inputHS{lib-code/Maybe}
+
+%**~footer
index 3837a47..e9415f1 100644 (file)
@@ -1,5 +1,5 @@
 %
-% $Header: /home/cvs/root/haskell-report/report/modules.verb,v 1.17 2002/12/02 11:22:02 simonpj Exp $
+% $Header: /home/cvs/root/haskell-report/report/modules.verb,v 1.18 2002/12/02 14:53:30 simonpj Exp $
 %
 %**<title>The Haskell 98 Report: Modules</title>
 %*section 5
@@ -383,6 +383,8 @@ entity was originally declared}.
 The ability to exclude the unqualified names allows full programmer control of
 the unqualified namespace: a locally defined entity can share the same
 name as a qualified import:
+\par
+{\small
 \bprog
 @
   module Ring where
@@ -395,7 +397,7 @@ name as a qualified import:
   succ = (Prelude.+ 1)
 @
 \eprog
-
+}
 
 \subsubsection{Local aliases}
 \label{as-clause}
diff --git a/report/monad.verb b/report/monad.verb
new file mode 100644 (file)
index 0000000..565065e
--- /dev/null
@@ -0,0 +1,189 @@
+%**<title>The Haskell 98 Library Report: Monad Utilities</title>
+%**~header
+\section{Monad Utilities}
+\label{Monad}
+
+\outline{
+\inputHS{lib-hdrs/Monad}
+}
+
+The @Monad@ library defines the @MonadPlus@ class, and 
+provides some useful operations on monads.
+
+\subsection{Naming conventions}
+
+The functions in this library use the following naming conventions:
+\begin{itemize}
+\item
+A postfix ``@M@'' always stands for a function in the Kleisli category:
+@m@ is added to function results (modulo currying) and nowhere else.
+So, for example,
+\bprog
+@
+  filter  ::            (a ->   Bool) -> [a] ->   [a]
+  filterM :: Monad m => (a -> m Bool) -> [a] -> m [a]
+@
+\eprog
+
+\item A postfix ``@_@'' changes the result type from @(m a)@ to @(m ())@.
+Thus (in the @Prelude@):
+\bprog
+@
+sequence  :: Monad m => [m a] -> m [a] 
+sequence_ :: Monad m => [m a] -> m () 
+@
+\eprog
+
+\item A prefix ``@m@'' generalises an existing function to a monadic form.
+Thus, for example:
+\bprog
+@
+  sum  :: Num a       => [a]   -> a
+  msum :: MonadPlus m => [m a] -> m a
+@
+\eprog
+\end{itemize}
+
+\subsection{Class @MonadPlus@}
+
+The @MonadPlus@ class is defined as follows:
+\bprog
+@
+class  Monad m => MonadPlus m  where
+    mzero  :: m a
+    mplus  :: m a -> m a -> m a
+@
+\eprog
+The class methods @mzero@ and @mplus@ are the zero and plus
+of the monad.
+
+Lists and the @Maybe@ type are instances of @MonadPlus@, thus:
+\bprog
+@
+instance  MonadPlus Maybe  where
+    mzero                 = Nothing
+    Nothing `mplus` ys    = ys
+    xs      `mplus` ys    = xs
+
+instance  MonadPlus []  where
+    mzero = []
+    mplus = (++)
+@
+\eprog
+
+
+\subsection{Functions}
+
+The @join@ function is the conventional monad join operator.  It is
+used to remove one level of monadic structure, projecting its bound
+argument into the outer level.
+
+% There is no convincing small-scale example for mapAndUnzipM
+The @mapAndUnzipM@ function maps its first argument over a list,
+returning the result as a pair of lists.  This function is mainly used
+with complicated data structures or a state-transforming monad.
+
+The @zipWithM@ function generalises @zipWith@ to arbitrary monads.
+For instance the following function displays a file, prefixing
+each line with its line number,
+\par
+{\small
+\bprog
+@
+listFile :: String -> IO ()
+listFile nm =
+  do cts <- readFile nm
+     zipWithM_ (\i line -> do putStr (show i); putStr ": "; putStrLn line)
+               [1..]
+               (lines cts)
+@
+\eprog
+}
+The @foldM@ function is analogous to @foldl@, except that its result
+is encapsulated in a monad.  Note that @foldM@ works from
+left-to-right over the list arguments.  This could be an issue where
+@(>>)@ and the ``folded function'' are not commutative. 
+\bprog
+@
+    foldM f a1 [x1, x2, ..., xm ]
+==  
+    do
+      a2 <- f a1 x1
+      a3 <- f a2 x2
+      ...
+      f am xm
+@
+\eprog
+If right-to-left
+evaluation is required, the input list should be reversed.
+
+% Omitted for now.  These functions are very useful in parsing libraries
+% - but in a slightly modified form:
+% o It is conventional to return the _longest_ parse first - not 
+%   shortest first.
+% o The function is too strict - you can't get any part of the result
+%   until the entire parse completes.  The fix is to use the function
+%   force when defining zeroOrMore.
+%   
+%     force :: Parser a -> Parser a
+%     force (P m) = P (\i -> let x = p i in
+%                            (fst (head x), snd (head x)) : tail x)
+%
+%   but how are we to generalise this to an arbitrary monad?
+%
+% The @zeroOrMore@ function performs an action repeatedly - returning
+% the list of all results obtained.  The @oneOrMore@ function is similar
+% but the action must succeed at least once.  That is,
+% \bprog
+% <at>
+% zeroOrMore m = zero ++ 
+%               [ [a0]       | a0 <- m ] ++
+%               [ [a0,a1]    | a0 <- m, a1 <- m ] ++
+%               [ [a0,a1,a2] | a0 <- m, a1 <- m, a2 <- m ] ++
+%               ...
+% 
+% oneOrMore m  = [ [a0]       | a0 <- m ] ++
+%               [ [a0,a1]    | a0 <- m, a1 <- m ] ++
+%               [ [a0,a1,a2] | a0 <- m, a1 <- m, a2 <- m ] ++
+%               ...
+% <at>
+% \eprog
+
+The @when@ and @unless@ functions provide conditional execution of
+monadic expressions.  For example,
+\bprog
+@
+when debug (putStr "Debugging\n")
+@
+\eprog
+will output the string @"Debugging\n"@ if the Boolean value @debug@ is
+@True@, and otherwise do nothing.
+
+The monadic lifting operators promote a function to a monad.  The
+function arguments are scanned left to right.  For example,
+\bprog
+@
+liftM2 (+) [0,1] [0,2] = [0,2,1,3]
+liftM2 (+) (Just 1) Nothing = Nothing
+@
+\eprog
+
+In many situations, the @liftM@ operations can be replaced by uses
+of @ap@, which promotes function application.
+\bprog
+@
+return f `ap` x1 `ap` ... `ap` xn
+@
+\eprog
+is equivalent to
+\bprog
+@
+liftMn f x1 x2 ... xn
+@
+\eprog
+\clearpage
+\subsection{Library {\tt Monad}}
+\inputHS{lib-code/Monad}
+
+%**~footer
+
diff --git a/report/numeric.verb b/report/numeric.verb
new file mode 100644 (file)
index 0000000..a00cfb0
--- /dev/null
@@ -0,0 +1,100 @@
+%**<title>The Haskell 98 Library Report: Numerics</title>
+%**~header
+\section{Numeric}
+\label{lib-numeric}
+
+\outline{
+\inputHS{lib-hdrs/Numeric}
+}
+This library contains assorted numeric functions, many of which are
+used in the standard Prelude.  
+
+In what follows, recall the following type definitions from the @Prelude@:
+\bprog
+@ 
+  type ShowS = String -> String
+  type ReadS = String -> [(a,String)]
+@
+\eprog
+
+\subsection{Showing functions}
+
+\begin{itemize}
+\item @showSigned :: (Real a) => (a -> ShowS) -> Int -> a -> ShowS@ \\ converts a
+possibly-negative @Real@ value of type @a@ to a string.  In the call "(@showSigned@ ~show ~prec ~val)",
+"val" is the value to show, "prec" is the precedence of the enclosing context, and "show" is
+a function that can show unsigned values.
+
+\item @showIntAtBase :: Integral a => a -> (Int -> Char) -> a -> ShowS@ \\
+shows a {\em non-negative} @Integral@ number using the base specified by the first argument,
+and the character representation specified by the second.
+
+\item @showInt, showOct, showHex :: Integral a => a -> ShowS@ \\ 
+show {\em non-negative} @Integral@ numbers in base 10, 8, and 16 respectively.
+
+\item 
+@showFFloat, showEFloat, showGFloat@ \\
+@    :: (RealFloat a) => Maybe Int -> a -> ShowS@ \\
+These three functions all show signed @RealFloat@ values:
+\begin{itemize}
+\item @showFFloat@ uses standard decimal notation (e.g. @245000@, @0.0015@).
+\item @showEFloat@ uses scientific (exponential) notation (e.g. @2.45e2@, @1.5e-3@).
+\item @showGFloat@ uses standard decimal notation for arguments whose absolute value lies 
+between @0.1@ and @9,999,999@, and scientific notation otherwise.
+\end{itemize}
+In the call "(@showEFloat@ ~digs ~val)", if "digs" is @Nothing@, the value is shown to full
+precision; if "digs" is "@Just@~ d", then at most "d" digits after the decimal point are shown.
+Exactly the same applies to the "digs" argument of the other two functions.
+
+\item @floatToDigits  :: (RealFloat a) => Integer -> a -> ([Int], Int)@ \\
+converts a base and a value to the representation of the value in digits, plus
+an exponent.  More specifically, if
+$$
+@floatToDigits@~b~r = @([@d_1, d_2, ... d_n@], @e@)@
+$$
+then the following properties hold:
+\begin{itemize}
+\item $r =  0.d_1 d_2 ..., d_n ~*~ b^e$
+\item $n \geq 0$
+\item $d_1 \neq 0 ~ \mbox{(when $n > 0$)}$
+\item $0 \leq d_i \leq b-1$
+\end{itemize}
+\end{itemize}
+
+\subsection{Reading functions}
+
+\begin{itemize}
+\item @readSigned :: (Real a) => ReadS a -> ReadS a@ \\ 
+reads a {\em signed} @Real@ value,
+given a reader for an unsigned value.
+
+\item @readInt :: (Integral a) => a -> (Char->Bool) -> (Char->Int) -> ReadS a@ \\
+reads an {\em unsigned} @Integral@ value in an arbitrary base.  In the call "(@readInt@~ base ~isdig ~d2i)",
+"base" is the base, "isdig" is a predicate distinguishing valid digits in this base, and "d2i" converts
+a valid digit character to an @Int@.
+
+\item @readFloat :: (RealFrac a) => ReadS a@ \\ 
+reads an {\em unsigned} @RealFrac@ value, expressed in decimal scientific notation.
+
+\item @readDec, readOct, readHex :: (Integral a) => ReadS a@  \\
+each read an unsigned number, in decimal, octal, and hexadecimal notation respectively.
+In the hexadecimal case, both upper or lower case letters are allowed.
+
+\item @lexDigits :: ReadS String@ reads a non-empty string of decimal digits.
+\end{itemize}
+(NB: @readInt@ is the ``dual'' of @showIntAtBase@, and @readDec@ is the ``dual'' of @showInt@.
+The inconsistent naming is a historical accident.)
+
+\subsection{Miscellaneous}
+
+\begin{itemize}
+\item @fromRat :: (RealFloat a) => Rational -> a@ converts a @Rational@ value
+into any type in class @RealFloat@.
+\end{itemize}
+
+\subsection{Library {\tt Numeric}}
+\inputHS{lib-code/Numeric}
+
+%**~footer
+
+
index f8c768b..b092317 100644 (file)
@@ -1,8 +1,7 @@
 %
-% $Header: /home/cvs/root/haskell-report/report/pragmas.verb,v 1.3 2001/08/23 16:41:41 simonpj Exp $
+% $Header: /home/cvs/root/haskell-report/report/pragmas.verb,v 1.4 2002/12/02 14:53:30 simonpj Exp $
 %
 %**<title>The Haskell 98 Report: Pragmas</title>
-%*section E
 %**~header
 \section{Compiler Pragmas}
 \label{pragmas}
index ed7cd19..b017f04 100644 (file)
@@ -277,7 +277,8 @@ Jose Labra,
 Jeff Lewis,
 Mark Lillibridge,
 % The doubled "" is turned into one by the verbatim preprocessor
-Bj\""{o}rn Lisper,
+% Bj\""{o}rn Lisper,
+Bjorn Lisper,
 Sandra Loosemore,
 Pablo Lopez,
 Olaf Lubeck, 
diff --git a/report/random.verb b/report/random.verb
new file mode 100644 (file)
index 0000000..9cccc7a
--- /dev/null
@@ -0,0 +1,273 @@
+%**<title>The Haskell 98 Library Report: Random Numbers</title>
+%**~eheader
+\section{Random Numbers}
+\label{random numbers}
+
+\outline {
+\inputHS{lib-hdrs/Random}
+}
+
+The @Random@ library deals with the common task of 
+pseudo-random number generation.  The library makes it possible to
+generate repeatable results, by starting with a specified initial
+random number generator; or to get different results on each run
+by using the system-initialised generator, or by supplying a seed
+from some other source.
+
+The library is split into two layers:
+\begin{itemize}
+\item A core {\em random number generator} provides a supply of bits.
+The class @RandomGen@ provides a common interface to such generators.
+
+\item The class @Random@ provides a way to extract particular values from
+a random number generator.  For example, the @Float@ instance of @Random@ 
+allows one to generate random values of type @Float@.
+\end{itemize}
+
+\subsection{The @RandomGen@ class, and the @StdGen@ generator}
+
+The class @RandomGen@ provides a common interface to random number generators.
+\bprog
+@
+  class RandomGen g where
+    genRange :: g -> (Int,Int)
+    next     :: g  -> (Int, g)
+    split    :: g -> (g, g)
+  
+    -- Default method
+    genRange g = (minBound,maxBound)
+@
+\eprog
+\indextt{next}
+\indextt{split}
+\indextt{genRange}
+\indextt{RandomGen}
+\begin{itemize}
+\item The @genRange@ operation yields the range of values returned by
+the generator. 
+
+It is required that:
+\begin{itemize}
+\item If $(a,b) ~=~ @genRange@~ g$, then $a < b$.
+\item $@genRange@~\bot ~\neq~ \bot$.  
+\end{itemize}
+The second condition ensures that @genRange@ cannot examine its
+argument, and hence the value it returns can be determined only by the
+instance of @RandomGen@.  That in turn allows an implementation to make
+a single call to @genRange@ to establish a generator's range, without
+being concerned that the generator returned by (say) @next@ might have a different
+range to the generator passed to @next@.
+
+\item The @next@ operation returns an @Int@ that is uniformly distributed
+in the range returned by @genRange@ (including both end points), and a new
+generator.
+
+\item The @split@ operation allows one to obtain two independent random number
+generators.  This is very useful in functional programs (for example, when
+passing a random number generator down to recursive calls), but very little work
+has been done on statistically robust implementations of @split@
+([1,4] are the only examples we know of).
+\end{itemize}
+
+The @Random@ library provides one instance of @RandomGen@, the abstract data
+type @StdGen@:
+\bprog
+@
+  data StdGen = ...    -- Abstract
+  
+  instance RandomGen StdGen where ...
+  instance Read      StdGen where ...
+  instance Show      StdGen where ...
+  
+  mkStdGen :: Int -> StdGen
+@
+\eprog
+\indextt{StdGen}
+\indextt{mkStdGen}
+The @StgGen@ instance of @RandomGen@ has a @genRange@ of at least 30 bits.
+
+The result of repeatedly using @next@ should be at least as
+statistically robust as the ``Minimal Standard Random Number Generator''
+described by [2,3].  Until more is known about implementations of @split@,
+all we require is that @split@ deliver generators that are (a) not identical
+and (b) independently robust in the sense just given.
+
+The @Show@/@Read@ instances of @StdGen@ provide a primitive way to save
+the state of a random number generator.
+It is required that @read (show g) == g@.
+
+In addition, @read@ may be used to map an arbitrary string (not
+necessarily one produced by @show@) onto a value of type @StdGen@.
+In general, the @read@ instance of @StdGen@ has the following properties:
+\begin{itemize}
+\item It guarantees to succeed on any string.
+\item It guarantees to consume only a finite portion of the string.
+\item Different argument strings are likely to result in different results.
+\end{itemize}
+
+The function @mkStdGen@ provides an alternative way of producing an initial generator,
+by mapping an @Int@ into a generator.  Again, distinct arguments should be likely
+to produce distinct generators.
+
+Programmers may, of course, supply their own instances of @RandomGen@.
+
+{\em Implementation warning.}  A superficially attractive implementation of @split@ is
+\bprog
+@
+  instance RandomGen MyGen where
+    ...
+    split g = (g, variantOf g)
+@
+\eprog
+Here, @split@ returns @g@ itself and a new generator derived from @g@.
+But now consider these two apparently-independent generators:
+\bprog
+@
+  g1 = snd (split g)
+  g2 = snd (split (fst (split g)))
+@
+\eprog
+If @split@ genuinely delivers independent generators (as specified), then @g1@ and
+@g2@ should be independent, but in fact they are both equal to @variantOf g@.
+Implementations of the above form do not meet the specification.
+
+\subsection{The @Random@ class}
+
+With a source of random number supply in hand, the @Random@ class allows
+the programmer to extract random values of a variety of types:
+\bprog
+@
+class Random a where
+   randomR :: RandomGen g => (a, a) -> g -> (a, g)
+   random  :: RandomGen g => g -> (a, g)
+
+   randomRs :: RandomGen g => (a, a) -> g -> [a]
+   randoms  :: RandomGen g => g -> [a]
+
+   randomRIO :: (a,a) -> IO a
+   randomIO :: IO a
+
+     -- Default methods
+   randoms g = x : randoms g' 
+                  where 
+                    (x,g') = random g
+   randomRs = ...similar...
+
+   randomIO        = getStdRandom random
+   randomRIO range = getStdRandom (randomR range)
+
+
+instance Random Int     where ...
+instance Random Integer where ...
+instance Random Float   where ...
+instance Random Double  where ...
+instance Random Bool    where ...
+instance Random Char    where ...
+@
+\eprog
+\indextt{Random}
+\indextt{random}
+\indextt{randomR}
+\indextt{randoms}
+\indextt{randomRs}
+\indextt{randomIO}
+\indextt{randomRIO}
+\begin{itemize}
+\item @randomR@ takes a range "(lo,hi)" and a random number generator "g",
+and returns a random value uniformly distributed in the closed interval "[lo,hi]", together
+with a new generator.  It is unspecified what happens if "lo>hi".
+For continuous types there is no requirement that the values "lo" and "hi" are
+ever produced, but they may be, depending on the implementation and the interval.
+
+% \begin{itemize}
+% \item For discrete types (such as @Int@ or @Bool@), 
+% ``uniformly distributed'' means that each value is equally likely to occur.
+% \item For floating-point types (instances of @Floating@, such as @Float@ or @Double@),
+% the probability of any particular (representable) value "v"
+% occurring is proportional to "ulp(v)/(h-l)", where "ulp(v)" is the
+% size of a unit change in the least significant bit position of "v".
+% \item For continuous types, such as @Rational@, ``uniformly distributed'' means
+% that the probability distribution of returned values is uniform over the interval.
+% \end{itemize}
+
+% \begin{itemize}
+% \item For discrete types (such as @Int@ or @Bool@), the range is the closed interval "[l,h]".
+% \item For fractional types (instances of @Fractional@, such as @Float@ or @Double@),
+% the range is the semi-closed interval "[l,h)".
+% \end{itemize}
+% for discrete types, or if "l \geq h" for fractional types.
+
+\item @random@ does the same as @randomR@, but does not take a range.
+\begin{itemize}
+\item For bounded types (instances of @Bounded@, such as @Char@), 
+the range is normally the whole type.
+\item For fractional types, the range is normally the semi-closed interval "[0,1)".
+\item For @Integer@, the range is (arbitrarily) the range of @Int@.
+\end{itemize}
+
+\item The plural versions, @randomRs@ and @randoms@, produce an infinite list of random
+values, and do not return a new generator.
+
+\item The @IO@ versions, @randomRIO@ and @randomIO@, use the global random number
+generator (see Section~\ref{global-rng}).
+\end{itemize}
+
+\subsection{The global random number generator}
+\label{global-rng}
+
+There is a single, implicit, global random number generator
+of type @StdGen@, held in some global variable maintained by the @IO@ monad.
+It is initialised automatically in some system-dependent fashion,
+for example, by using the time of day, or Linux's kernel random number generator.
+To get deterministic behaviour, use @setStdGen@.
+\bprog
+@
+  setStdGen    :: StdGen -> IO ()      
+  getStdGen    :: IO StdGen            
+  newStdGen    :: IO StdGen
+  getStdRandom :: (StdGen -> (a, StdGen)) -> IO a
+@
+\eprog
+\indextt{setStdGen}
+\indextt{getStdGen}
+\indextt{newStdGen}
+\indextt{getStdRandom}
+\begin{itemize}
+\item @getStdGen@ and @setStdGen@ get and set the global random
+number generator, respectively.
+
+\item @newStdGen@ applies @split@ to the current global random generator,
+updates it with one of the results, and returns the other.
+
+\item @getStdRandom@ uses the supplied function to get a value from
+the current global random generator, and updates the
+global generator with the new generator returned by the function.
+For example, @rollDice@ gets a random integer between 1 and 6:
+\bprog
+@
+  rollDice :: IO Int
+  rollDice = getStdRandom (randomR (1,6))
+@
+\eprog
+\end{itemize}    
+
+\subsection*{References}
+\begin{description}
+\item[{[1]}] FW Burton and RL Page, ``Distributed random number generation'',
+       Journal of Functional Programming, 2(2):203-212, April 1992.
+
+\item[{[2]}] SK Park, and KW Miller, ``Random number generators - good ones are hard to find'',
+       Comm ACM 31(10), Oct 1988, pp1192-1201.
+
+\item[{[3]}] DG Carta, ``Two fast implementations of the minimal standard random number generator'',
+       Comm ACM, 33(1), Jan 1990, pp87-88.
+
+\item[{[4]}] P Hellekalek, ``Don't trust parallel Monte Carlo'', Department of Mathematics,
+University of Salzburg, @http://random.mat.sbg.ac.at/~peter/pads98.ps@, 1998.
+\end{description}
+
+The Web site @http://random.mat.sbg.ac.at/@ is a great source of information.
+
+
+%**~efooter
+
diff --git a/report/ratio.verb b/report/ratio.verb
new file mode 100644 (file)
index 0000000..95f0c69
--- /dev/null
@@ -0,0 +1,53 @@
+%**<title>The Haskell 98 Library Report: Rational Numbers</title>
+%**~header
+\section{Rational Numbers}
+\index{rational numbers}
+
+\outline{
+\inputHS{lib-hdrs/Ratio}
+}
+
+For each @Integral@ type $t$, there is
+a type @Ratio@\indextycon{Ratio} $t$ of rational pairs with components of
+type $t$.  The type name @Rational@\indexsynonym{Rational} is a synonym for
+@Ratio Integer@.  
+
+@Ratio@ is an instance of classes @Eq@, @Ord@, @Num@, @Real@, 
+@Fractional@, @RealFrac@, @Enum@, @Read@, and @Show@.  In each case,
+the instance for $@Ratio@~t$ simply ``lifts'' the corresponding operations
+over $t$.  If $t$ is a bounded type, the results may be unpredictable;
+for example @Ratio Int@ may give rise to integer overflow even for
+rational numbers of small absolute size.
+
+The operator @(%)@\index{%@@{\tt {\char'045}}} forms the ratio of two
+integral numbers, reducing the fraction to terms with no common factor
+and such that the denominator is positive.  The functions
+@numerator@\indextt{numerator}
+and @denominator@\indextt{denominator} extract the components of a
+ratio; these are in reduced form with a positive denominator.
+@Ratio@ is an abstract type.  For example, @12 % 8@ is reduced to 3/2
+and @12 % (-8)@ is reduced to (-3)/2.
+
+The @approxRational@ function, applied to two real fractional numbers
+@x@ and @epsilon@, returns the simplest rational number within the open
+interval "(@x@-@epsilon@, @x@+@epsilon@)".
+A rational number "n/d" in reduced form is said to
+be simpler than another "n'/d'" if "|n| \leq |n'|" and "d \leq d'".
+Note that it can be proved that any real interval contains a unique
+simplest rational.
+
+
+%% Deleted the following -- this is implementation detail -- KH/AD.
+% ; here, for simplicity, we assume a closed rational
+% interval.  If such an interval includes at least one whole number, then
+% the simplest rational is the absolutely least whole number.  Otherwise,
+% the bounds are of the form "q/1 + r/d" and "q/1 + r'/d'", where "|r| < d"
+% and "|r'| < d'", and the simplest rational is "q/1" + the reciprocal of
+% the simplest rational between "d'/r'" and "d/r".
+
+\clearpage
+\subsection{Library {\tt Ratio}}
+\label{Ratio}
+\inputHS{lib-code/Ratio}
+
+%**~footer
index 592b463..4eab317 100644 (file)
@@ -1,14 +1,13 @@
 %
-% $Header: /home/cvs/root/haskell-report/report/standard-prelude.verb,v 1.2 2001/12/21 16:00:25 simonpj Exp $
+% $Header: /home/cvs/root/haskell-report/report/standard-prelude.verb,v 1.3 2002/12/02 14:53:30 simonpj Exp $
 %
 %**<title>The Haskell 98 Report: Standard Prelude</title>
-%*section A
 %**~header
 %*anchor on
 \section{Standard Prelude}
 \label{stdprelude}
 
-In this appendix the entire \Haskell{} Prelude is given.  It constitutes
+In this chapter the entire \Haskell{} Prelude is given.  It constitutes
 a {\em specification} for the Prelude.  Many of the definitions are
 written with clarity rather than efficiency in mind, 
 and it is not required that the specification be implemented as shown here.
@@ -69,7 +68,6 @@ versions are given in the @List@ library, with the prefix
 \subsection{Prelude {\tt PreludeList}}
 \label{preludelist}
 \inputHS{PreludeList}\clearpage
-
 \subsection{Prelude {\tt PreludeText}}
 \label{preludetext}
 \inputHS{PreludeText}\cleardoublepage
@@ -77,7 +75,6 @@ versions are given in the @List@ library, with the prefix
 \subsection{Prelude {\tt PreludeIO}}
 \label{preludeio}
 \inputHS{PreludeIO}
-
 %**~footer
 
 
index 804f023..5d8fa96 100644 (file)
@@ -1,8 +1,7 @@
 %
-% $Header: /home/cvs/root/haskell-report/report/syntax-iso.verb,v 1.9 2002/12/02 11:22:02 simonpj Exp $
+% $Header: /home/cvs/root/haskell-report/report/syntax-iso.verb,v 1.10 2002/12/02 14:53:30 simonpj Exp $
 %
 %**<title>Haskell 98 Syntax</title>
-%*section B
 %**~header
 \section{Syntax Reference}
 \label{syntax}
diff --git a/report/system.verb b/report/system.verb
new file mode 100644 (file)
index 0000000..d8abf12
--- /dev/null
@@ -0,0 +1,64 @@
+%**<title>The Haskell 98 Library Report: System functions</title>
+%**~header
+
+\section{System Functions}
+
+\outline{
+\inputHS{lib-hdrs/System}
+}
+\indextt{ExitCode}\indextt{ExitSuccess}\indextt{ExitFailure}
+\indextt{getArgs}\indextt{getProgName}\indextt{getEnv}
+\indextt{system}\indextt{exitWith}\indextt{exitFailure}
+
+%% It would be less draconian to return [] for operations
+%% other than system, exitWith. KH
+This library describes the interaction of the program with the
+operating system.  
+
+Any @System@ operation could raise an @isIllegalOperation@, as
+described in Section~\ref{IOError}; all other permissible errors are
+described below.  Note that, in particular, if an implementation does
+not support an operation it must raise an @isIllegalOperation@.
+
+The @ExitCode@ type defines the exit codes that a program can return.
+@ExitSuccess@ indicates successful termination; and @ExitFailure@
+"code" indicates program failure with value "code".  The exact
+interpretation of "code" is operating-system dependent.  In
+particular, some values of "code" may be prohibited (for instance, 0 on a
+POSIX-compliant system).
+
+Computation @getArgs@ returns a list of the program's command
+line arguments (not including the program name)\index{program arguments}.
+Computation @getProgName@ returns the name of the program
+as it was invoked\index{program name}.
+Computation @getEnv@~"var" returns the value
+of the environment variable "var"\index{environment variables}.
+If variable "var" is undefined, the
+@isDoesNotExistError@ exception is raised.
+Computation @system@~"cmd" returns the exit code produced when the
+operating system processes the command "cmd"\index{operating system
+commands}.
+
+Computation @exitWith@~"code" terminates the program, returning "code"
+to the program's caller\index{terminating a program}.  Before the
+program terminates, any open or semi-closed handles are first closed.
+The caller may interpret the return code as it wishes, but the program
+should return @ExitSuccess@ to mean normal completion, and
+@ExitFailure @"n" to mean that the program encountered a problem from
+which it could not recover.  The value @exitFailure@ is equal to
+@exitWith (ExitFailure @"exitfail"@)@, where "exitfail" is
+implementation-dependent.  @exitWith@ bypasses the error handling in
+the I/O monad and cannot be intercepted by @catch@.
+
+If a program terminates as a result of calling @error@\indextt{error} or
+because its value is otherwise determined to be "\bot"\index{"\bot"}, then it
+is treated identically to the computation @exitFailure@.  Otherwise, if any
+program "p" terminates without calling @exitWith@ explicitly, it is treated
+identically to the computation
+\bprog
+@(@"p"@ >> exitWith ExitSuccess) `catch` \ _ -> exitFailure@
+\eprog
+\indextt{catch}
+
+%**~footer
diff --git a/report/time.verb b/report/time.verb
new file mode 100644 (file)
index 0000000..e1d3594
--- /dev/null
@@ -0,0 +1,76 @@
+%**<title>The Haskell 98 Library Report: Dates and Times</title>
+%**~header
+\section{Dates and Times}
+\label{time}
+\index{time}
+\index{time of day}\index{clock time}
+
+%% Note: HBC has Leap year calculations too.
+%% My feeling is that these are unnecessary given the much stronger
+%% ability here to find the differences between dates.
+
+\outline {
+\inputHS{lib-hdrs/Time}
+}
+\outline{
+\inputHS{lib-hdrs/Time1}
+}
+
+The @Time@ library provides standard functionality for clock times,
+including timezone information. It follows RFC~1129 in its use of
+Coordinated Universal Time (UTC).
+
+@ClockTime@ is an abstract type, used for the system's internal clock
+time.  Clock times may be compared directly or converted to a calendar
+time @CalendarTime@ for I/O or other manipulations.
+@CalendarTime@ is a user-readable and manipulable representation of
+the internal @ClockTime@ type.  The numeric fields have the following
+ranges.
+\outline{
+\begin{tabbing}
+\ignorehtml{
+\ \ \ \=ctpicosec\ \ \ \ \=-maxInt\ \=\ldots\ \=$(10^{12})-1$\ \ \ \ \ \=\kill}
+\>\underline{Value}\>\>\underline{Range}\>\>\underline{Comments} \\
+\\
+\>ctYear\>\>-maxInt\'$\ldots$\>maxInt\>Pre-Gregorian dates are inaccurate \\
+\>ctDay\>\>1\'$\ldots$\>31 \\
+\>ctHour\>\>0\'$\ldots$\>23\\
+\>ctMin\>\>0\'$\ldots$\>59\\
+\>ctSec\>\>0\'$\ldots$\>61\>Allows for two Leap Seconds\\
+\>ctPicosec\>\>0\'$\ldots$\>$(10^{12})-1$ \\
+\>ctYDay\>\>0\'$\ldots$\>365\>364 in non-Leap years \\
+\>ctTZ\>\>-89999\'$\ldots$\>89999\>Variation from UTC in seconds
+\end{tabbing}
+}
+The "ctTZName" field is the name of the time zone.  The "ctIsDST" field
+is @True@ if Daylight Savings Time would be in effect, and @False@
+otherwise.
+The @TimeDiff@ type records the difference between two clock times in
+a user-readable way.
+
+Function @getClockTime@ returns the current time in its internal
+representation.  The expression
+@addToClockTime@~"d"~"t" adds a time difference "d" and a
+clock time "t" to yield a new clock time.  The difference "d" may be either
+positive or negative.  The expression @diffClockTimes@~"t1"~"t2"
+returns the difference between two clock times "t1" and "t2" as a
+@TimeDiff@. 
+
+Function @toCalendarTime@~"t" converts "t" to a local time, modified
+by the timezone and daylight savings time settings in force at the
+time of conversion.  Because of this dependence on the local environment,
+@toCalendarTime@ is in the @IO@ monad.
+
+Function @toUTCTime@~"t" converts "t" into a @CalendarTime@
+in standard UTC format.
+@toClockTime@~"l" converts "l" into the corresponding internal
+@ClockTime@ ignoring the contents of the "ctWDay", "ctYDay",
+"ctTZName", and "ctIsDST" fields.
+
+Function @calendarTimeToString@ formats
+calendar times using local conventions and a formatting string.
+
+\subsection{Library {\tt Time}}
+\inputHS{lib-code/Time}
+
+%**~header