Commit 086a885e authored by Simon Peyton Jones's avatar Simon Peyton Jones
Browse files

--------------------------------

	This version should typeset the
	Haskell 98 language and libraries
	as a single book rather than as
	two separate reports.
	--------------------------------
parent 0e597cc5
......@@ -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 \
......
......@@ -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) $<
%**<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
%
% $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
......
%**<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
%**<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
%**<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
%
% $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.''
......
%
% $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
......
%**<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