summaryrefslogtreecommitdiff
path: root/doc/reference/examples.verb.tex
diff options
context:
space:
mode:
Diffstat (limited to 'doc/reference/examples.verb.tex')
-rw-r--r--doc/reference/examples.verb.tex5494
1 files changed, 0 insertions, 5494 deletions
diff --git a/doc/reference/examples.verb.tex b/doc/reference/examples.verb.tex
deleted file mode 100644
index 24bcb5c363..0000000000
--- a/doc/reference/examples.verb.tex
+++ /dev/null
@@ -1,5494 +0,0 @@
-%% $Id$
-
-\documentclass[11pt]{book}
-
-\usepackage{fleqn,a4wide,vquote,modefs,math,prooftree,scaladefs}
-\newcommand{\exercise}{\paragraph{Exercise:}}
-\newcommand{\rewriteby}[1]{\mbox{\tab\tab\rm(#1)}}
-
-\title{Scala By Examples}
-
-\author{
-Martin Odersky \\ LAMP/EPFL
-}
-
-\sloppy
-\begin{document}
-\maketitle
-\bibliographystyle{alpha}
-
-\chapter{\label{chap:intro}Introduction}
-
-\input{rationale-chapter.tex}
-
-The rest of this document is structured as
-follows. Chapters~\ref{chap:example-one} and
-\ref{chap:example-auction} highlight some of the features that make
-Scala interesting. The following chapters introduce the language
-constructs of Scala in a more thorough
-way. Chapter~\ref{chap:simple-funs} introduces basic expressions and
-simple functions. Chapter~\ref{chap:first-class-funs} introduces
-higher-order functions. (to be continued).
-
-This document ows a great dept to Sussman and Abelson's wonderful book
-``Structure and Interpretation of Computer
-Programs''\cite{abelson-sussman:structure}. Many of their examples and
-exercises are also present here. Of course, the working language has
-in each case been changed from Scheme to Scala. Furthermore, the
-examples make use of Scala's object-oriented constructs where
-appropriate.
-
-
-\chapter{\label{chap:example-one}A First Example}
-
-As a first example, here is an implementation of Quicksort in Scala.
-\begin{verbatim}
-def sort(xs: Array[int]): unit = {
-
- def swap(i: int, j: int): unit = {
- val t = xs(i); xs(i) = xs(j); xs(j) = t;
- }
-
- def sort1(l: int, r: int): unit = {
- val pivot = xs((l + r) / 2);
- var i = l, j = r;
- while (i <= j) {
- while (xs(i) < pivot) { i = i + 1 }
- while (xs(j) > pivot) { j = j - 1 }
- if (i <= j) {
- swap(i, j);
- i = i + 1;
- j = j - 1;
- }
- }
- if (l < j) sort1(l, j);
- if (j < r) sort1(i, r);
- }
-
- sort1(0, xs.length - 1);
-}
-\end{verbatim}
-The implementation looks quite similar to what one would write in Java
-or C. We use the same operators and similar control structures.
-There are also some minor syntactical differences. In particular:
-\begin{itemize}
-\item
-Definitions start with a reserved word. Function definitions start
-with \verb@def@, variable definitions start with \verb@var@ and
-definitions of values (i.e. read only variables) start with \verb@val@.
-\item
-The declared type of a symbol is given after the symbol and a colon.
-The declared type can often be omitted, because the compiler can infer
-it from the context.
-\item
-We use \verb@unit@ instead of \verb@void@ to define the result type of
-a procedure.
-\item
-Array types are written \verb@Array[T]@ rather than \verb@T[]@,
-and array selections are written \verb@a(i)@ rather than \verb@a[i]@.
-\item
-Functions can be nested inside other functions. Nested functions can
-access parameters and local variables of enclosing functions. For
-instance, the name of the array \verb@a@ is visible in functions
-\verb@swap@ and \verb@sort1@, and therefore need not be passed as a
-parameter to them.
-\end{itemize}
-So far, Scala looks like a fairly conventional language with some
-syntactic pecularities. In fact it is possible to write programs in a
-conventional imperative or object-oriented style. This is important
-because it is one of the things that makes it easy to combine Scala
-components with components written in mainstream languages such as
-Java, C\# or Visual Basic.
-
-However, it is also possible to write programs in a style which looks
-completely different. Here is Quicksort again, this time written in
-functional style.
-
-\begin{verbatim}
-def sort(xs: List[int]): List[int] = {
- val pivot = a(a.length / 2);
- sort(a.filter(x => x < pivot))
- ::: a.filter(x => x == pivot)
- ::: sort(a.filter(x => x > pivot))
-}
-\end{verbatim}
-
-The functional program works with lists instead of arrays.\footnote{In
-a future complete implemenetation of Scala, we could also have used arrays
-instead of lists, but at the moment arrays do not yet support
-\verb@filter@ and \verb@:::@.}
-It captures the essence of the quicksort algorithm in a concise way:
-\begin{itemize}
-\item Pick an element in the middle of the list as a pivot.
-\item Partition the lists into two sub-lists containing elements that
-are less than, respectively greater than the pivot element, and a
-third list which contains elements equal to privot.
-\item Sort the first two sub-lists by a recursive invocation of
-the sort function.\footnote{This is not quite what the imperative algorithm does;
-the latter partitions the array into two sub-arrays containing elements
-less than or greater or equal to pivot.}
-\item The result is obtained by appending the three sub-lists together.
-\end{itemize}
-Both the imperative and the functional implementation have the same
-asymptotic complexity -- $O(N;log(N))$ in the average case and
-$O(N^2)$ in the worst case. But where the imperative implementation
-operates in place by modifying the argument array, the functional
-implementation returns a new sorted list and leaves the argument
-list unchanged. The functional implementation thus requires more
-transient memory than the imperative one.
-
-The functional implementation makes it look like Scala is a language
-that's specialized for functional operations on lists. In fact, it
-is not; all of the operations used in the example are simple library
-methods of a class \verb@List[t]@ which is part of the standard
-Scala library, and which itself is implemented in Scala.
-
-In particular, there is the method \verb@filter@ which takes as
-argument a {\em predicate function} that maps list elements to
-boolean values. The result of \verb@filter@ is a list consisting of
-all the elements of the original list for which the given predicate
-function is true. The \verb@filter@ method of an object of type
-\verb@List[t]@ thus has the signature
-\begin{verbatim}
- def filter(p: t => boolean): List[t] .
-\end{verbatim}
-Here, \verb@t => boolean@ is the type of functions that take an element
-of type \verb@t@ and return a \verb@boolean@. Functions like
-\verb@filter@ that take another function as argument or return one as
-result are called {\em higher-order} functions.
-
-In the quicksort program, \verb@filter@ is applied three times to an
-anonymous function argument. The first argument,
-\verb@x => x <= pivot@ represents the function that maps its parameter
-\verb@x@ to the boolean value \verb@x <= pivot@. That is, it yields
-true if \verb@x@ is smaller or equal than \verb@pivot@, false
-otherwise. The function is anonymous, i.e.\ it is not defined with a
-name. The type of the \verb@x@ parameter is omitted because a Scala
-compiler can infer it automatically from the context where the
-function is used. To summarize, \verb@xs.filter(x => x <= pivot)@
-returns a list consisting of all elements of the list \verb@xs@ that are
-smaller than \verb@pivot@.
-
-\comment{
-It is also possible to apply higher-order functions such as
-\verb@filter@ to named function arguments. Here is functional
-quicksort again, where the two anonymous functions are replaced by
-named auxiliary functions that compare the argument to the
-\verb@pivot@ value.
-
-\begin{verbatim}
-def sort (xs: List[int]): List[int] = {
- val pivot = xs(xs.length / 2);
- def leqPivot(x: int) = x <= pivot;
- def gtPivot(x: int) = x > pivot;
- def eqPivot(x: int) = x == pivot;
- sort(xs filter leqPivot)
- ::: sort(xs filter eqPivot)
- ::: sort(xs filter gtPivot)
-}
-\end{verbatim}
-}
-
-An object of type \verb@List[t]@ also has a method ``\verb@:::@''
-which takes an another list and which returns the result of appending this
-list to itself. This method has the signature
-\begin{verbatim}
- def :::(that: List[t]): List[t] .
-\end{verbatim}
-Scala does not distinguish between identifiers and operator names. An
-identifier can be either a sequence of letters and digits which begins
-with a letter, or it can be a sequence of special characters, such as
-``\verb@+@'', ``\verb@*@'', or ``\verb@:@''. The last definition thus
-introduced a new method identifier ``\verb@:::@''. This identifier is
-used in the Quicksort example as a binary infix operator that connects
-the two sub-lists resulting from the partition. In fact, any method
-can be used as an operator in Scala. The binary operation $E;op;E'$
-is always interpreted as the method call $E.op(E')$. This holds also
-for binary infix operators which start with a letter. The recursive call
-to \verb@sort@ in the last quicksort example is thus equivalent to
-\begin{verbatim}
- sort(a.filter(x => x < pivot))
- .:::(sort(a.filter(x => x == pivot)))
- .:::(sort(a.filter(x => x > pivot))) .
-\end{verbatim}
-
-Looking again in detail at the first, imperative implementation of
-Quicksort, we find that many of the language constructs used in the
-second solution are also present, albeit in a disguised form.
-
-For instance, ``standard'' binary operators such as \verb@+@,
-\verb@-@, or \verb@<@ are not treated in any special way. Like
-\verb@append@, they are methods of their left operand. Consequently,
-the expression \verb@i + 1@ is regarded as the invocation
-\verb@i.+(1)@ of the \verb@+@ method of the integer value \verb@x@.
-Of course, a compiler is free (if it is moderately smart, even expected)
-to recognize the special case of calling the \verb@+@ method over
-integer arguments and to generate efficient inline code for it.
-
-Control constructs such as \verb@while@ are also not primitive but are
-predefined functions in the standard Scala library. Here is the
-definition of \verb@while@ in Scala.
-\begin{verbatim}
-def while (def p: boolean) (def s: unit): unit = if (p) { s ; while(p)(s) }
-\end{verbatim}
-The \verb@while@ function takes as first parameter a test function,
-which takes no parameters and yields a boolean value. As second
-parameter it takes a command function which also takes no parameters
-and yields a trivial result. \verb@while@ invokes the command function
-as long as the test function yields true. Again, compilers are free to
-pick specialized implementations of \verb@while@ that have the same
-behavior as the invocation of the function given above.
-
-\chapter{\label{chap:example-auction}Programming with Actors and Messages}
-
-Here's an example that shows an application area for which Scala is
-particularly well suited. Consider the task of implementing an
-electronic auction service. We use an Erlang-style actor process
-model to implement the participants of the auction. Actors are
-objects to which messages are sent. Every process has a ``mailbox'' of
-its incoming messages which is represented as a queue. It can work
-sequentially through the messages in its mailbox, or search for
-messages matching some pattern.
-
-For every traded item there is an auctioneer process that publishes
-information about the traded item, that accepts offers from clients
-and that communicates with the seller and winning bidder to close the
-transaction. We present an overview of a simple implementation
-here.
-
-As a first step, we define the messages that are exchanged during an
-auction. There are two abstract base classes (called {\em traits}):
-\verb@AuctionMessage@ for messages from clients to the auction
-service, and \verb@AuctionReply@ for replies from the service to the
-clients. These are defined as follows.
-\begin{verbatim}
-trait AuctionMessage;
-case class
- Offer(bid: int, client: Actor), \=// make a bid
- Inquire(client: Actor) extends AuctionMessage; \>// inquire status
-
-trait AuctionReply;
-case class
- Status(asked: int, expiration: Date), \>// asked sum, expiration date
- BestOffer, \>// yours is the best offer
- BeatenOffer(maxBid: int), \>// offer beaten by maxBid
- AuctionConcluded(seller: Actor, client: Actor), \>// auction concluded
- AuctionFailed, \>// failed with no bids
- AuctionOver extends AuctionReply; \>// bidding is closed
-\end{verbatim}
-
-\begin{figure}[htb]
-\begin{verbatim}
-class Auction(seller: Actor, minBid: int, closing: Date) extends Actor {
- val timeToShutdown = 36000000; // msec
- val bidIncrement = 10;
- def execute {
- var maxBid = minBid - bidIncrement;
- var maxBidder: Actor = _;
- var running = true;
- while (running) {
- receiveWithin ((closing.getTime() - new Date().getTime())) {
- case Offer(bid, client) =>
- if (bid >= maxBid + bidIncrement) {
- if (maxBid >= minBid) maxBidder send BeatenOffer(bid);
- maxBid = bid; maxBidder = client; client send BestOffer;
- } else {
- client send BeatenOffer(maxBid);
- }
-
- case Inquire(client) =>
- client send Status(maxBid, closing);
-
- case TIMEOUT =>
- if (maxBid >= minBid) {
- val reply = AuctionConcluded(seller, maxBidder);
- maxBidder send reply; seller send reply;
- } else {
- seller send AuctionFailed;
- }
- receiveWithin(timeToShutdown) {
- case Offer(_, client) => client send AuctionOver
- case TIMEOUT => running = false;
- }}}}}
-\end{verbatim}
-\caption{\label{fig:simple-auction}Implementation of an Auction Service}
-\end{figure}
-
-For each base class, there are a number of {\em case classes} which
-define the format of particular messages in the class. These messages
-might well be ultimately mapped to small XML documents. We expect
-automatic tools to exist that convert between XML documents and
-internal data structures like the ones defined above.
-
-Figure~\ref{fig:simple-auction} presents a Scala implementation of a
-class \verb@Auction@ for auction processes that coordinate the bidding
-on one item. Objects of this class are created by indicating
-\begin{itemize}
-\item
-a seller process which needs to be notified when the auction is over,
-\item
-a minimal bid,
-\item
-the date when the auction is to be closed.
-\end{itemize}
-The process behavior is defined by its \verb@run@ method. That method
-repeatedly selects (using \verb@receiveWithin@) a message and reacts to it,
-until the auction is closed, which is signalled by a \verb@TIMEOUT@
-message. Before finally stopping, it stays active for another period
-determined by the \verb@timeToShutdown@ constant and replies to
-further offers that the auction is closed.
-
-Here are some further explanations of the constructs used in this
-program:
-\begin{itemize}
-\item
-The \verb@receiveWithin@ method of class \verb@Actor@ takes as
-parameters a time span given in milliseconds and a function that
-processes messages in the mailbox. The function is given by a sequence
-of cases that each specify a pattern and an action to perform for
-messages matching the pattern. The \verb@receiveWithin@ method selects
-the first message in the mailbox which matches one of these patterns
-and applies the corresponding action to it.
-\item
-The last case of \verb@receiveWithin@ is guarded by a
-\verb@TIMEOUT@ pattern. If no other messages are received in the meantime, this
-pattern is triggered after the time span which is passed as argument
-to the enclosing \verb@receiveWithin@ method. \verb@TIMEOUT@ is a
-particular instance of class \verb@Message@, which is triggered by the
-\verb@Actor@ implementation itself.
-\item
-Reply messages are sent using syntax of the form
-\verb@destination send SomeMessage@. \verb@send@ is used here as a
-binary operator with a process and a message as arguments. This is
-equivalent in Scala to the method call
-\verb@destination.send(SomeMessage)@, i.e. the invocation of
-the \verb@send@ of the destination process with the given message as
-parameter.
-\end{itemize}
-The preceding discussion gave a flavor of distributed programming in
-Scala. It might seem that Scala has a rich set of language constructs
-that support actor processes, message sending and receiving,
-programming with timeouts, etc. In fact, the opposite is true. All the
-constructs discussed above are offered as methods in the library class
-\verb@Actor@. That class is itself implemented in Scala, based on the underlying
-thread model of the host language (e.g. Java, or .NET).
-The implementation of all features of class \verb@Actor@ used here is
-given in Section~\ref{sec:actors}.
-
-The advantages of this approach are relative simplicity of the core
-language and flexibility for library designers. Because the core
-language need not specify details of high-level process communication,
-it can be kept simpler and more general. Because the particular model
-of messages in a mailbox is a library module, it can be freely
-modified if a different model is needed in some applications. The
-approach requires however that the core language is expressive enough
-to provide the necessary language abstractions in a convenient
-way. Scala has been designed with this in mind; one of its major
-design goals was that it should be flexible enough to act as a
-convenient host language for domain specific languages implemented by
-library modules. For instance, the actor communication constructs
-presented above can be regarded as one such domain specific language,
-which conceptually extends the Scala core.
-
-\chapter{\label{chap:simple-funs}Expressions and Simple Functions}
-
-The previous examples gave an impression of what can be done with
-Scala. We now introduce its constructs one by one in a more
-systematic fashion. We start with the smallest level, expressions and
-functions.
-
-\section{Expressions And Simple Functions}
-
-A Scala system comes with an interpreter which can be seen as a
-fancy calculator. A user interacts with the calculator by typing in
-expressions and obtaining the results of their evaluation. Example:
-
-\begin{verbatim}
-? 87 + 145
-232
-
-? 1000 - 333
-667
-
-? 5 + 2 * 3
-11
-\end{verbatim}
-It is also possible to name a sub-expression and use the name instead
-of the expression afterwards:
-\begin{verbatim}
-? def size = 2
-def size: int
-
-? 5 * size
-10
-\end{verbatim}
-\begin{verbatim}
-? def pi = 3.14159
-def pi: double
-
-? def radius = 10
-def radius: int
-
-
-? 2 * pi * radius
-62.8318
-\end{verbatim}
-Definitions start with the reserved word \verb@def@; they introduce a
-name which stands for the expression following the \verb@=@ sign. The
-interpreter will answer with the introduced name and its type.
-
-Executing a definition such as \verb@def x = e@ will not evaluate the
-expression \verb@e@. Instead \verb@e@ is evaluated whenever \verb@x@
-is used. Alternatively, Scala offers a value definition
-\verb@val x = e@, which does evaluate the right-hand-side \verb@e@ as part of the
-evaluation of the definition. If \verb@x@ is then used subsequently,
-it is immediately replaced by the pre-computed value of
-\verb@e@, so that the expression need not be evaluated again.
-
-How are expressions evaluated? An expression consisting of operators
-and operands is evaluated by repeatedly applying the following
-simplification steps.
-\begin{itemize}
-\item pick the left-most operation
-\item evaluate its operands
-\item apply the operator to the operand values.
-\end{itemize}
-A name defined by \verb@def@\ is evaluated by replacing the name by the
-definition's right hand side. A name defined by \verb@val@ is
-evaluated by replacing the name by the value of the definitions's
-right-hand side. The evaluation process stops once we have reached a
-value. A value is some data item such as a string, a number, an array,
-or a list.
-
-\example
-Here is an evaluation of an arithmetic expression.
-\begin{verbatim}
- \=(2 * pi) * radius
--> \>(2 * 3.14159) * radius
--> \>6.28318 * radius
--> \>6.28318 * 10
--> \>62.8318
-\end{verbatim}
-The process of stepwise simplification of expressions to values is
-called {\em reduction}.
-
-\section{Parameters}
-
-Using \verb@def@, one can also define functions with parameters. Example:
-\begin{verbatim}
-? def square(x: double) = x * x
-def square(x: double): double
-
-? square(2)
-4.0
-
-? square(5 + 4)
-81.0
-
-? square(square(4))
-256.0
-
-? def sumOfSquares(x: double, y: double) = square(x) + square(y)
-def sumOfSquares(x: double, y: double): double
-\end{verbatim}
-
-Function parameters follow the function name and are always enclosed
-in parentheses. Every parameter comes with a type, which is indicated
-following the parameter name and a colon. At the present time, we only
-need basic numeric types such as the type \verb@double@ of double
-precision numbers. These are written as in Java.
-
-Functions with parameters are evaluated analogously to operators in
-expressions. First, the arguments of the function are evaluated (in
-left-to-right order). Then, the function application is replaced by
-the function's right hand side, and at the same time all formal
-parameters of the function are replaced by their corresponding actual
-arguments.
-
-\example\
-
-\begin{verbatim}
- \=sumOfSquares(3, 2+2)
--> \>sumOfSquares(3, 4)
--> \>square(3) + square(4)
--> \>3 * 3 + square(4)
--> \>9 + square(4)
--> \>9 + 4 * 4
--> \>9 + 16
--> \>25
-\end{verbatim}
-
-The example shows that the interpreter reduces function arguments to
-values before rewriting the function application. One could instead
-have chosen to apply the function to unreduced arguments. This would
-have yielded the following reduction sequence:
-\begin{verbatim}
- \= sumOfSquares(3, 2+2)
--> \>square(3) + square(2+2)
--> \>3 * 3 + square(2+2)
--> \>9 + square(2+2)
--> \>9 + (2+2) * (2+2)
--> \>9 + 4 * (2+2)
--> \>9 + 4 * 4
--> \>9 + 16
--> \>25
-\end{verbatim}
-
-The second evaluation order is known as \emph{call-by-name},
-whereas the first one is known as \emph{call-by-value}. For
-expressions that use only pure functions and that therefore can be
-reduced with the substitution model, both schemes yield the same final
-values.
-
-Call-by-value has the advantage that it avoids repeated evaluation of
-arguments. Call-by-name has the advantage that it avoids evaluation of
-arguments when the parameter is not used at all by the function.
-Call-by-value is usually more efficient than call-by-name, but a
-call-by-value evaluation might loop where a call-by-name evaluation
-would terminate. Consider:
-\begin{verbatim}
-? def loop: int = loop
-def loop: int
-
-? def first(x: int, y: int) = x
-def first(x: int, y: int): int
-\end{verbatim}
-Then \verb@first(1, loop)@ reduces with call-by-name to \verb@1@,
-whereas the same term reduces with call-by-value repeatedly to itself,
-hence evaluation does not terminate.
-\begin{verbatim}
- \=first(1, loop)
--> \>first(1, loop)
--> \>first(1, loop)
--> \>...
-\end{verbatim}
-Scala uses call-by-value by default, but it switches to call-by-name evaluation
-if the parameter is preceded by \verb@def@.
-
-\example\
-
-\begin{verbatim}
-? def constOne(x: int, def y: int) = 1
-constOne(x: int, def y: int): int
-
-? constOne(1, loop)
-1
-
-? constOne(loop, 2) // gives an infinite loop.
-^C
-\end{verbatim}
-
-\section{Conditional Expressions}
-
-Scala's \verb@if-else@ lets one choose between two alternatives. Its
-syntax is like Java's \verb@if-else@. But where Java's \verb@if-else@
-can be used only as an alternative of statements, Scala allows the
-same syntax to choose between two expressions. Scala's \verb@if-else@
-hence also replaces Java's conditional expression \verb@ ... ? ... :
-...@.
-
-\example\
-
-\begin{verbatim}
-? def abs(x: double) = if (x >= 0) x else -x
-abs(x: double): double
-\end{verbatim}
-Scala's boolean expressions are similar to Java's; they are formed
-from the constants
-\verb@true@ and
-\verb@false@, comparison operators, boolean negation \verb@!@ and the
-boolean operators \verb@&&@ and \verb@||@.
-
-\section{\label{sec:sqrt}Example: Square Roots by Newton's Method}
-
-We now illustrate the language elements introduced so far in the
-construction of a more interesting program. The task is to write a
-function
-\begin{verbatim}
-def sqrt(x: double): double = ...
-\end{verbatim}
-which computes the square root of \verb@x@.
-
-A common way to compute square roots is by Newton's method of
-successive approximations. One starts with an initial guess \verb@y@
-(say: \verb@y = 1@). One then repeatedly improves the current guess
-\verb@y@ by taking the average of \verb@y@ and \verb@x/y@.
-As an example, the next three columns indicate the guess \verb@y@, the
-quotient \verb@x/y@, and their average for the first approximations of
-$\sqrt 2$.
-\begin{verbatim}
-1 \=2/1 = 2 \=1.5
-1.5 \>2/1.5 = 1.3333 \>1.4167
-1.4167 \>2/1.4167 = 1.4118 \>1.4142
-1.4142 \>... \>...
-
-y \>x/y \>(y + x/y)/2
-\end{verbatim}
-One can implement this algorithm in Scala by a set of small functions,
-which each represent one of the elements of the algorithm.
-
-We first define a function for iterating from a guess to the result:
-\begin{verbatim}
-def sqrtIter(guess: double, x: double): double =
- if (isGoodEnough(guess, x)) guess
- else sqrtIter(improve(guess, x), x);
-\end{verbatim}
-Note that \verb@sqrtIter@ calls itself recursively. Loops in
-imperative programs can always be modelled by recursion in functional
-programs.
-
-Note also that the definition of \verb@sqrtIter@ contains a return
-type, which follows the parameter section. Such return types are
-mandatory for recursive functions. For a non-recursive function, the
-return type is optional; if it is missing the type checker will
-compute it from the type of the function's right-hand side. However,
-even for non-recursive functions it is often a good idea to include a
-return type for better documentation.
-
-As a second step, we define the two functions called by
-\verb@sqrtIter@: a function to \verb@improve@ the guess and a
-termination test \verb@isGoodEnough@. Here's their definition.
-\begin{verbatim}
-def improve(guess: double, x: double) =
- (guess + x / guess) / 2;
-
-def isGoodEnough(guess: double, x: double) =
- abs(square(guess) - x) < 0.001;
-\end{verbatim}
-
-Finally, the \verb@sqrt@ function itself is defined by an aplication
-of \verb@sqrtIter@.
-\begin{verbatim}
-def sqrt(x: double) = sqrtIter(1.0, x);
-\end{verbatim}
-
-\exercise The \verb@isGoodEnough@ test is not very precise for small numbers
-and might lead to non-termination for very large ones (why?).
-Design a different version \verb@isGoodEnough@ which does not have these problems.
-
-\exercise Trace the execution of the \verb@sqrt(4)@ expression.
-
-\section{Nested Functions}
-
-The functional programming style encourages the construction of many
-small helper functions. In the last example, the implementation
-of \verb@sqrt@ made use of the helper functions
-\verb@sqrtIter@, \verb@improve@ and
-\verb@isGoodEnough@. The names of these functions
-are relevant only for the implementation of
-\verb@sqrt@. We normally do not want users of \verb@sqrt@ to acess these functions
-directly.
-
-We can enforce this (and avoid name-space pollution) by including
-the helper functions within the calling function itself:
-\begin{verbatim}
-def sqrt(x: double) = {
- def sqrtIter(guess: double, x: double): double =
- if (isGoodEnough(guess, x)) guess
- else sqrtIter(improve(guess, x), x);
-
- def improve(guess: double, x: double) =
- (guess + x / guess) / 2;
-
- def isGoodEnough(guess: double, x: double) =
- abs(square(guess) - x) < 0.001;
-
- sqrtIter(1.0, x)
-}
-\end{verbatim}
-In this program, the braces \verb@{ ... }@ enclose a {\em block}.
-Blocks in Scala are themselves expressions. Every block ends in a
-result expression which defines its value. The result expression may
-be preceded by auxiliary definitions, which are visible only in the
-block itself.
-
-Every definition in a block must be followed by a semicolon, which
-separates this definition from subsequent definitions or the result
-expression. However, a semicolon is inserted implicitly if the
-definition ends in a right brace and is followed by a new line.
-Therefore, the following are all legal:
-\begin{verbatim}
-def f(x) = x + 1; /* `;' mandatory */
-f(1) + f(2)
-
-def g(x) = {x + 1}
-g(1) + g(2)
-
-def h(x) = {x + 1}; /* `;' mandatory */ h(1) + h(2)
-\end{verbatim}
-Scala uses the usual block-structured scoping rules. A name defined in
-some outer block is visible also in some inner block, provided it is
-not redefined there. This rule permits us to simplify our
-\verb@sqrt@ example. We need not pass \verb@x@ around as an additional parameter of
-the nested functions, since it is always visible in them as a
-parameter of the outer function \verb@sqrt@. Here is the simplified code:
-\begin{verbatim}
-def sqrt(x: double) = {
- def sqrtIter(guess: double): double =
- if (isGoodEnough(guess)) guess
- else sqrtIter(improve(guess));
-
- def improve(guess: double) =
- (guess + x / guess) / 2;
-
- def isGoodEnough(guess: double) =
- abs(square(guess) - x) < 0.001;
-
- sqrtIter(1.0)
-}
-\end{verbatim}
-
-\section{Tail Recursion}
-
-Consider the following function to compute the greatest common divisor
-of two given numbers.
-
-\begin{verbatim}
-def gcd(a: int, b: int): int = if (b == 0) a else gcd(b, a % b)
-\end{verbatim}
-
-Using our substitution model of function evaluation,
-\verb@gcd(14, 21)@ evaluates as follows:
-
-\begin{verbatim}
- \=gcd(14, 21)
--> \>if (21 == 0) 14 else gcd(21, 14 % 21)
--> \>if (false) 14 else gcd(21, 14 % 21)
--> \>gcd(21, 14 % 21)
--> \>gcd(21, 14)
--> \>if (14 == 0) 21 else gcd(14, 21 % 14)
--> -> \>gcd(14, 21 % 14)
--> \>gcd(14, 7)
--> \>if (7 == 0) 14 else gcd(7, 14 % 7)
--> -> \>gcd(7, 14 % 7)
--> \>gcd(7, 0)
--> \>if (0 == 0) 7 else gcd(0, 7 % 0)
--> -> \>7
-\end{verbatim}
-
-Contrast this with the evaluation of another recursive function,
-\verb@factorial@:
-
-\begin{verbatim}
-def factorial(n: int): int = if (n == 0) 1 else n * factorial(n - 1)
-\end{verbatim}
-
-The application \verb@factorial(5)@ rewrites as follows:
-\begin{verbatim}
- \=factorial(5)
--> \>if (5 == 0) 1 else 5 * factorial(5 - 1)
--> \>5 * factorial(5 - 1)
--> \>5 * factorial(4)
--> ... -> \>5 * (4 * factorial(3))
--> ... -> \>5 * (4 * (3 * factorial(2)))
--> ... -> \>5 * (4 * (3 * (2 * factorial(1))))
--> ... -> \>5 * (4 * (3 * (2 * (1 * factorial(0))))
--> ... -> \>5 * (4 * (3 * (2 * (1 * 1))))
--> ... -> \>120
-
-\end{verbatim}
-There is an important difference between the two rewrite sequences:
-The terms in the rewrite sequence of \verb@gcd@ have again and again
-the same form. As evaluation proceeds, their size is bounded by a
-constant. By contrast, in the evaluation of factorial we get longer
-and longer chains of operands which are then multiplied in the last
-part of the evaluation sequence.
-
-Even though actual implementations of Scala do not work by rewriting
-terms, they nevertheless should have the same space behavior as in the
-rewrite sequences. In the implementation of \verb@gcd@, one notes that
-the recursive call to \verb@gcd@ is the last action performed in the
-evaluation of its body. One also says that \verb@gcd@ is
-``tail-recursive''. The final call in a tail-recursive function can be
-implemented by a jump back to the beginning of that function. The
-arguments of that call can overwrite the parameters of the current
-instantiation of \verb@gcd@, so that no new stack space is needed.
-Hence, tail recursive functions are iterative processes, which can be
-executed in constant space.
-
-By contrast, the recursive call in \verb@factorial@ is followed by a
-multiplication. Hence, a new stack frame is allocated for the
-recursive instance of factorial, and is decallocated after that
-instance has finished. The given formulation of the factorial function
-is not tail-recursive; it needs space proportional to its input
-parameter for its execution.
-
-More generally, if the last action of a function is a call to another
-(possibly the same) function, only a single stack frame is needed for
-both functions. Such calls are called ``tail calls''. In principle,
-tail calls can always re-use the stack frame of the calling function.
-However, some run-time environments (such as the Java VM) lack the
-primititives to make stack frame re-use for tail calls efficient. A
-production quality Scala implementation is therefore only required to re-use
-the stack frame of a directly tail-recursive function whose last
-action is a call to itself. Other tail calls might be optimized also,
-but one should not rely on this across
-implementations\footnote{The current Scala implementation is not yet
-production quality; it never optimizes tail calls, not even directly
-recursive ones}.
-
-\exercise Design a tail-recursive version of
-\verb@factorial@.
-
-\chapter{\label{chap:first-class-funs}First-Class Functions}
-
-A function in Scala is a ``first-class value''. Like any other value,
-it may be passed as a parameter or returned as a result. Functions
-which take other functions as parameters or return them as results are
-called {\em higher-order} functions. This chapter introduces
-higher-order functions and shows how they provide a flexible mechanism
-for program composition.
-
-As a motivating example, consider the following three related tasks:
-\begin{enumerate}
-\item
-Write a function to sum all integers between two given numbers \verb@a@ and \verb@b@:
-\begin{verbatim}
-def sumInts(a: int, b: int): double =
- if (a > b) 0 else a + sumInts(a + 1, b)
-\end{verbatim}
-\item
-Write a function to sum the cubes of all integers between two given numbers
-\verb@a@ and \verb@b@:
-\begin{verbatim}
-def cube(x: int): double = x * x * x
-def sumCubes(a: int, b: int): double =
- if (a > b) 0 else cube(a) + sumSqrts(a + 1, b)
-\end{verbatim}
-\item
-Write a function to sum the reciprocals of all integers between two given numbers
-\verb@a@ and \verb@b@:
-\begin{verbatim}
-def sumReciprocals(a: int, b: int): double =
- if (a > b) 0 else 1.0 / a + sumReciprocals(a + 1, b)
-\end{verbatim}
-\end{enumerate}
-These functions are all instances of
-\(\sum^b_a f(n)\) for different values of $f$.
-We can factor out the common pattern by defining a function \verb@sum@:
-\begin{verbatim}
-def sum(f: int => double, a: int, b: int): double =
- if (a > b) 0 else f(a) + sum(f, a + 1, b)
-\end{verbatim}
-The type \verb@int => double@ is the type of functions that
-take arguments of type \verb@int@ and return results of type
-\verb@double@. So \verb@sum@ is a function which takes another function as
-a parameter. In other words, \verb@sum@ is a {\em higher-order}
-function.
-
-Using \verb@sum@, we can formulate the three summing functions as
-follows.
-\begin{verbatim}
-def sumInts(a: int, b: int): double = sum(id, a, b);
-def sumCubes(a: int, b: int): double = sum(cube, a, b);
-def sumReciprocals(a: int, b: int): double = sum(reciprocal, a, b);
-\end{verbatim}
-where
-\begin{verbatim}
-def id(x: int): double = x;
-def cube(x: int): double = x * x * x;
-def reciprocal(x: int): double = 1.0/x;
-\end{verbatim}
-
-\section{Anonymous Functions}
-
-Parameterization by functions tends to create many small functions. In
-the previous example, we defined \verb@id@, \verb@cube@ and
-\verb@reciprocal@ as separate functions, so that they could be
-passed as arguments to \verb@sum@.
-
-Instead of using named function definitions for these small argument
-functions, we can formulate them in a shorter way as {\em anonymous
-functions}. An anonymous function is an expression that evaluates to a
-function; the function is defined without giving it a name. As an
-example consider the anonymous reciprocal function:
-\begin{verbatim}
- x: int => 1.0/x
-\end{verbatim}
-The part before the arrow `\verb@=>@' is the parameter of the function,
-whereas the part following the `\verb@=>@' is its body. If there are
-several parameters, we need to enclose them in parentheses. For
-instance, here is an anonymous function which multiples its two arguments.
-\begin{verbatim}
- (x: double, y: double) => x * y
-\end{verbatim}
-Using anonymous functions, we can reformulate the three summation
-functions without named auxiliary functions:
-\begin{verbatim}
-def sumInts(a: int, b: int): double = sum(x: int => x, a, b);
-def sumCubes(a: int, b: int): double = sum(x: int => x * x * x, a, b);
-def sumReciprocals(a: int, b: int): double = sum(x: int => 1.0/x, a, b);
-\end{verbatim}
-Often, the Scala compiler can deduce the parameter type(s) from the
-context of the anonymous function. In this case, they can be omitted.
-For instance, in the case of \verb@sumInts@, \verb@sumCubes@ and
-\verb@sumReciprocals@, one knows from the type of
-\verb@sum@ that the first parameter must be a function of type
-\verb@int => double@. Hence, the parameter type \verb@int@ is
-redundant and may be omitted:
-\begin{verbatim}
-def sumInts(a: int, b: int): double = sum(x => x, a, b);
-def sumCubes(a: int, b: int): double = sum(x => x * x * x, a, b);
-def sumReciprocals(a: int, b: int): double = sum(x => 1.0/x, a, b);
-\end{verbatim}
-
-Generally, the Scala term
-\verb@(x$_1$: T$_1$, ..., x$_n$: T$_n$) => E@
-defines a function which maps its parameters
-\verb@x$_1$, ..., x$_n$@ to the result of the expression \verb@E@
-(where \verb@E@ may refer to \verb@x$_1$, ..., x$_n$@). Anonymous
-functions are not essential language elements of Scala, as they can
-always be expressed in terms of named functions. Indeed, the
-anonymous function
-\verb@(x$_1$: T$_1$, ..., x$_n$: T$_n$) => E@
-is equivalent to the block
-\begin{verbatim}
-{ def f (x$_1$: T$_1$, ..., x$_n$: T$_n$) = E ; f }
-\end{verbatim}
-where \verb@f@ is fresh name which is used nowhere else in the program.
-We also say, anonymous functions are ``syntactic sugar''.
-
-\section{Currying}
-
-The latest formulation of the three summing function is already quite
-compact. But we can do even better. Note that
-\verb@a@ and \verb@b@ appear as parameters and arguments of every function
-but they do not seem to take part in interesting combinations. Is
-there a way to get rid of them?
-
-Let's try to rewrite \verb@sum@ so that it does not take the bounds
-\verb@a@ and \verb@b@ as parameters:
-\begin{verbatim}
-def sum(f: int => double) = {
- def sumF(a: int, b: int): double =
- if (a > b) 0 else f(a) + sumF(a + 1, b);
- sumF
-}
-\end{verbatim}
-In this formulation, \verb@sum@ is a function which returns another
-function, namely the specialized summing function \verb@sumF@. This
-latter function does all the work; it takes the bounds \verb@a@ and
-\verb@b@ as parameters, applies \verb@sum@'s function parameter \verb@f@ to all
-integers between them, and sums up the results.
-
-Using this new formulation of \verb@sum@, we can now define:
-\begin{verbatim}
-def sumInts = sum(x => x);
-def sumCubes = sum(x => x * x * x);
-def sumReciprocals = sum(x => 1.0/x);
-\end{verbatim}
-Or, equivalently, with value definitions:
-\begin{verbatim}
-val sumInts = sum(x => x);
-val sumCubes = sum(x => x * x * x);
-val sumReciprocals = sum(x => 1.0/x);
-\end{verbatim}
-These functions can be applied like other functions. For instance,
-\begin{verbatim}
-? sumCubes(1, 10) + sumReciprocals (10, 20)
-3025.7687714031754
-\end{verbatim}
-How are function-returning functions applied? As an example, in the expression
-\begin{verbatim}
-sum (x => x * x * x) (1, 10) ,
-\end{verbatim}
-the function \verb@sum@ is applied to the cubing function
-\verb@(x => x * x * x)@. The resulting function is then
-applied to the second argument list, \verb@(1, 10)@.
-
-This notation is possible because function application associates to the left.
-That is, if $args_1$ and $args_2$ are argument lists, then
-\bda{lcl}
-f(args_1)(args_2) & \ \ \mbox{is equivalent to}\ \ & (f(args_1))(args_2)
-\eda
-In our example, \verb@sum(x => x * x * x)(1, 10)@ is equivalent to
-\verb@(sum(x => x * x * x))(1, 10)@.
-
-The style of function-returning functions is so useful that Scala has
-special syntax for it. For instance, the next definition of \verb@sum@
-is equivalent to the previous one, but is shorter:
-\begin{verbatim}
-def sum(f: int => double)(a: int, b: int): double =
- if (a > b) 0 else f(a) + sum(f)(a + 1, b)
-\end{verbatim}
-Generally, a curried function definition
-\begin{verbatim}
-def f (args$_1$) ... (args$_n$) = E
-\end{verbatim}
-where $n > 1$ expands to
-\begin{verbatim}
-def f (args$_1$) ... (args$_{n-1}$) = { def g (args$_n$) = E ; g }
-\end{verbatim}
-where \verb@g@ is a fresh identifier. Or, shorter, using an anonymous function:
-\begin{verbatim}
-def f (args$_1$) ... (args$_{n-1}$) = ( args$_n$ ) => E .
-\end{verbatim}
-Performing this step $n$ times yields that
-\begin{verbatim}
-def f (args$_1$) ... (args$_n$) = E
-\end{verbatim}
-is equivalent to
-\begin{verbatim}
-def f = (args$_1$) => ... => (args$_n$) => E .
-\end{verbatim}
-Or, equivalently, using a value definition:
-\begin{verbatim}
-val f = (args$_1$) => ... => (args$_n$) => E .
-\end{verbatim}
-This style of function definition and application is called {\em
-currying} after its promoter, Haskell B.\ Curry, a logician of the
-20th century, even though the idea goes back further to Moses
-Sch\"onfinkel and Gottlob Frege.
-
-The type of a function-returning function is expressed analogously to
-its parameter list. Taking the last formulation of \verb@sum@ as an example,
-the type of \verb@sum@ is \verb@(int => double) => (int, int) => double@.
-This is possible because function types associate to the right. I.e.
-\begin{verbatim}
-T$_1$ => T$_2$ => T$_3$ \=$\mbox{is equivalent to}$ \=T$_1$ => (T$_2$ => T$_3$) .
-\end{verbatim}
-
-\subsection*{Exercises:}
-
-1. The \verb@sum@ function uses a linear recursion. Can you write a
-tail-recursive one by filling in the ??'s?
-
-\begin{verbatim}
-def sum(f: int => double)(a: int, b: int): double = {
- def iter (a, result) = {
- if (??) ??
- else iter (??, ??)
- }
- iter (??, ??)
-}
-\end{verbatim}
-
-2. Write a function \verb@product@ that computes the product of the
-values of functions at points over a given range.
-
-3. Write \verb@factorial@ in terms of \verb@product@.
-
-4. Can you write an even more general function which generalizes both
-\verb@sum@ and \verb@product@?
-
-\section{Example: Finding Fixed Points of Functions}
-
-A number \verb@x@ is called a {\em fixed point} of a function \verb@f@ if
-\begin{verbatim}
-f(x) = x .
-\end{verbatim}
-For some functions \verb@f@ we can locate the fixed point by beginning
-with an initial guess and then applying \verb@f@ repeatedly, until the
-value does not change anymore (or the change is within a small
-tolerance). This is possible if the sequence
-\begin{verbatim}
-x, f(x), f(f(x)), f(f(f(x))), ...
-\end{verbatim}
-converges to fixed point of $f$. This idea is captured in
-the following ``fixed-point finding function'':
-\begin{verbatim}
-val tolerance = 0.0001;
-def isCloseEnough(x: double, y: double) = abs((x - y) / x) < tolerance;
-def fixedPoint(f: double => double)(firstGuess: double) = {
- def iterate(guess: double): double = {
- val next = f(guess);
- if (isCloseEnough(guess, next)) next
- else iterate(next)
- }
- iterate(firstGuess)
-}
-\end{verbatim}
-We now apply this idea in a reformulation of the square root function.
-Let's start with a specification of \verb@sqrt@:
-\begin{verbatim}
-sqrt(x) \== $\mbox{the {\sl y} such that}$ y * y = x
- \>= $\mbox{the {\sl y} such that}$ y = x / y
-\end{verbatim}
-Hence, \verb@sqrt(x)@ is a fixed point of the function \verb@y => x / y@.
-This suggests that \verb@sqrt(x)@ can be computed by fixed point iteration:
-\begin{verbatim}
-def sqrt(x: double) = fixedPoint(y => x / y)(1.0)
-\end{verbatim}
-Unfortunately, this does not converge. Let's instrument the fixed point
-function with a print statement which keeps track of the current
-\verb@guess@ value:
-\begin{verbatim}
-def fixedPoint(f: double => double)(firstGuess: double) = {
- def iterate(guess: double): double = {
- val next = f(guess);
- System.out.println(next);
- if (isCloseEnough(guess, next)) next
- else iterate(next)
- }
- iterate(firstGuess)
-}
-\end{verbatim}
-Then, \verb@sqrt(2)@ yields:
-\begin{verbatim}
- 2.0
- 1.0
- 2.0
- 1.0
- 2.0
- ...
-\end{verbatim}
-One way to control such oscillations is to prevent the guess from changing too much.
-This can be achieved by {\em averaging} successive values of the original sequence:
-\begin{verbatim}
-> def sqrt(x: double) = fixedPoint(y => (y + x/y) / 2)(1.0)
-> sqrt(2.0)
- 1.5
- 1.4166666666666665
- 1.4142156862745097
- 1.4142135623746899
- 1.4142135623746899
-\end{verbatim}
-In fact, expanding the \verb@fixedPoint@ function yields exactly our
-previous definition of fixed point from Section~\ref{sec:sqrt}.
-
-The previous examples showed that the expressive power of a language
-is considerably enhanced if functions can be passed as arguments. The
-next example shows that functions which return functions can also be
-very useful.
-
-Consider again fixed point iterations. We started with the observation
-that $\sqrt(x)$ is a fixed point of the function \verb@y => x / y@.
-Then we made the iteration converge by averaging successive values.
-This technique of {\em average dampening} is so general that it
-can be wrapped in another function.
-\begin{verbatim}
-def averageDamp(f: double => double)(x: double) = (x + f(x)) / 2
-\end{verbatim}
-Using \verb@averageDamp@, we can reformulate the square root function
-as follows.
-\begin{verbatim}
-def sqrt(x: double) = fixedPoint(averageDamp(y => x/y))(1.0)
-\end{verbatim}
-This expresses the elements of the algorithm as clearly as possible.
-
-\exercise Write a function for cube roots using \verb@fixedPoint@ and
-\verb@averageDamp@.
-
-\section{Summary}
-
-We have seen in the previous chapter that functions are essential
-abstractions, because they permit us to introduce general methods of
-computing as explicit, named elements in our programming language.
-The current chapter has shown that these abstractions can be combined by
-higher-order functions to create further abstractions. As
-programmers, we should look out for opportunities to abstract and to
-reuse. The highest possible level of abstraction is not always the
-best, but it is important to know abstraction techniques, so that one
-can use abstractions where appropriate.
-
-\section{Language Elements Seen So Far}
-
-Chapters~\ref{chap:simple-funs} and \ref{chap:first-class-funs} have
-covered Scala's language elements to express expressions and types
-comprising of primitive data and functions. The context-free syntax
-of these language elements is given below in extended Backus-Naur
-form, where `\verb@|@' denotes alternatives, \verb@[...]@ denotes
-option (0 or 1 occurrences), and \verb@{...}@ denotes repetition (0 or
-more occurrences).
-
-\subsection*{Characters}
-
-Scala programs are sequences of (Unicode) characters. We distinguish the
-following character sets:
-\begin{itemize}
-\item
-whitespace, such as `\verb@ @', tabulator, or newline characters,
-\item
-letters `\verb@a@' to `\verb@z@', `\verb@A@' to `\verb@Z@',
-\item
-digits \verb@`0'@ to `\verb@9@',
-\item
-the delimiter characters
-\begin{verbatim}
-. , ; ( ) { } [ ] \ " '
-\end{verbatim}
-\item
-operator characters, such as `\verb@#@' `\verb@+@',
-`\verb@:@'. Essentially, these are printable characters which are
-in none of the character sets above.
-\end{itemize}
-
-\subsection*{Lexemes:}
-
-\begin{verbatim}
-ident ::= letter {letter | digit} | operator { operator } | ident `_' ident
-literal ::= $\mbox{``as in Java''}$
-\end{verbatim}
-
-Literals are as in Java. They define numbers, characters, strings, or
-boolean values. Examples of literals as \verb@0@, \verb@1.0d10@, \verb@'x'@,
-\verb@"he said \"hi!\""@, or \verb@true@.
-
-Identifiers can be of two forms. They either start with a letter,
-which is followed by a (possibly empty) sequence of letters or
-symbols, or they start with an operator character, which is followed
-by a (possibly empty) sequence of operator characters. Both forms of
-identifiers may contain underscore characters `\verb@_@'. Furthermore,
-an underscore character may be followed by either sort of
-identifier. Hence, the following are all legal identifiers:
-\begin{verbatim}
-x Room10a + -- foldl_: +_vector
-\end{verbatim}
-It follows from this rule that subsequent operator-identifiers need to
-be separated by whitespace. For instance, the input
-\verb@x+-y@ is parsed as the three token sequence \verb@x@, \verb@+-@,
-\verb@y@. If we want to express the sum of \verb@x@ with the
-negated value of \verb@y@, we need to add at least one space,
-e.g. \verb@x+ -y@.
-
-The `\verb@\$@' character is reserved for compiler-generated
-identifiers; it should not be used in source programs. %$
-
-The following are reserved words, they may not be used as identifiers:
-\begin{verbatim}
-abstract case catch class def
-do else extends false final
-finally for if import new
-null object override package private
-protected return sealed super this
-trait try true type val
-var while with yield
-_ : = => <- <: >: # @
-\end{verbatim}
-
-\subsection*{Types:}
-
-\begin{verbatim}
-Type \= = SimpleType | FunctionType
-FunctionType \> = SimpleType `=>' Type | `(' [Types] `)' `=>' Type
-SimpleType \> = byte | short | char | int | long | double | float | boolean | unit | String
-Types \> = Type {`,' Type}
-\end{verbatim}
-
-Types can be:
-\begin{itemize}
-\item number types \verb@byte@, \verb@short@, \verb@char@, \verb@int@, \verb@long@, \verb@float@ and \verb@double@ (these are as in Java),
-\item the type \verb@boolean@ with values \verb@true@ and \verb@false@,
-\item the type \verb@unit@ with the only value \verb@{}@,
-\item the type \verb@String@,
-\item function types such as \verb@(int, int) => int@ or \verb@String => Int => String@.
-\end{itemize}
-
-\subsection*{Expressions:}
-
-\begin{verbatim}
-Expr \= = InfixExpr | FunctionExpr | if `(' Expr `)' Expr else Expr
-InfixExpr \> = PrefixExpr | InfixExpr Operator InfixExpr
-Operator \> = ident
-PrefixExpr \> = [`+' | `-' | `!' | `~' ] SimpleExpr
-SimpleExpr \> = ident | literal | SimpleExpr `.' ident | Block
-FunctionExpr\> = Bindings `=> Expr
-Bindings \> = ident [`:' SimpleType] | `(' [Binding {`,' Binding}] `)'
-Binding \> = ident [`:' Type]
-Block \> = `{' {Def `;'} Expr `}'
-\end{verbatim}
-
-Expressions can be:
-\begin{itemize}
-\item
-identifiers such as \verb@x@, \verb@isGoodEnough@, \verb@*@, or \verb@+-@,
-\item
-literals, such as \verb@0@, \verb@1.0@, or \verb@"abc"@,
-\item
-field and method selections, such as \verb@System.out.println@,
-\item
-function applications, such as \verb@sqrt(x)@,
-\item
-operator applications, such as \verb@-x@ or \verb@y + x@,
-\item
-conditionals, such as \verb@if (x < 0) -x else x@,
-\item
-blocks, such as \verb@{ val x = abs(y) ; x * 2 }@,
-\item
-anonymous functions, such as \verb@x => x + 1@ or \verb@(x: int, y: int) => x + y@.
-\end{itemize}
-
-\subsection*{Definitions:}
-
-\begin{verbatim}
-Def \= = \=FunDef | ValDef
-FunDef \> = \>def ident {`(' [Parameters] `)'} [`:' Type] `=' Expr
-ValDef \> = \>val ident [`:' Type] `=' Expr
-Parameters \> = \>Parameter {`,' Parameter}
-Parameter \> = \>[def] ident `:' Type
-\end{verbatim}
-Definitions can be:
-\begin{itemize}
-\item
-function definitions such as \verb@def square(x: int) = x * x@,
-\item
-value definitions such as \verb@val y = square(2)@.
-\end{itemize}
-
-\chapter{Classes and Objects}
-\label{chap:classes}
-
-Scala does not have a built-in type of rational numbers, but it is
-easy to define one, using a class. Here's a possible implementation.
-
-\begin{verbatim}
-class Rational(n: int, d: int) {
- private def gcd(x: int, y: int): int = {
- if (x == 0) y
- else if (x < 0) gcd(-x, y)
- else if (y < 0) -gcd(x, -y)
- else gcd(y % x, x);
- }
- private val g = gcd(n, d);
-
- val numer: int = n/g;
- val denom: int = d/g;
- def +(that: Rational) =
- new Rational(numer * that.denom + that.numer * denom, denom * that.denom);
- def -(that: Rational) =
- new Rational(numer * that.denom - that.numer * denom, denom * that.denom);
- def *(that: Rational) =
- new Rational(numer * that.numer, denom * that.denom);
- def /(that: Rational) =
- new Rational(numer * that.denom, denom * that.numer);
-}
-\end{verbatim}
-This defines \verb@Rational@ as a class which takes two constructor
-arguments \verb@n@ and \verb@d@, containing the number's numerator and
-denominator parts. The class provides fields which return these parts
-as well as methods for arithmetic over rational numbers. Each
-arithmetic method takes as parameter the right operand of the
-operation. The left operand of the operation is always the rational
-number of which the method is a member.
-
-\paragraph{Private members.}
-The implementation of rational numbers defines a private method
-\verb@gcd@ which computes the greatest common denominator of two
-integers, as well as a private field \verb@g@ which contains the
-\verb@gcd@ of the constructor arguments. These members are inaccessible
-outside class \verb@Rational@. They are used in the implementation of
-the class to eliminate common factors in the constructor arguments in
-order to ensure that nominator and denominator are always in
-normalized form.
-
-\paragraph{Creating and Accessing Objects.}
-As an example of how rational numbers can be used, here's a program
-that prints the sum of all numbers $1/i$ where $i$ ranges from 1 to 10.
-\begin{verbatim}
-var i = 1;
-var x = Rational(0, 1);
-while (i <= 10) {
- x = x + Rational(1,i);
- i = i + 1;
-}
-System.out.println(x.numer + "/" + x.denom);
-\end{verbatim}
-The \verb@+@ operation converts both its operands to strings and returns the
-concatenation of the result strings. It thus corresponds to \verb@+@ in Java.
-
-\paragraph{Inheritance and Overriding.}
-Every class in Scala has a superclass which it extends.
-Excepted is only the root class \verb@Object@, which does not have a
-superclass, and which is indirectly extended by every other class.
-If a class does not mention a superclass in its definition, the root
-class \verb@Object@ is implicitly assumed. For instance, class
-\verb@Rational@ could equivalently be defined as
-\begin{verbatim}
-class Rational(n: int, d: int) extends Object {
- ... // as before
-}
-\end{verbatim}
-A class inherits all members from its superclass. It may also redefine
-(or: {\em override}) some inherited members. For instance, class
-\verb@Object@ defines
-a method
-\verb@toString@ which returns a representation of the object as a string:
-\begin{verbatim}
-class Object {
- ...
- def toString(): String = ...
-}
-\end{verbatim}
-The implementation of \verb@toString@ in \verb@Object@
-forms a string consisting of the object's class name and a number. It
-makes sense to redefine this method for objects that are rational
-numbers:
-\begin{verbatim}
-class Rational(n: int, d: int) extends Object {
- ... // as before
- override def toString() = numer + "/" + denom;
-}
-\end{verbatim}
-Note that, unlike in Java, redefining definitions need to be preceded
-by an \verb@override@ modifier.
-
-If class $A$ extends class $B$, then objects of type $A$ may be used
-wherever objects of type $B$ are expected. We say in this case that
-type $A$ {\em conforms} to type $B$. For instance, \verb@Rational@
-conforms to \verb@Object@, so it is legal to assign a \verb@Rational@
-value to a variable of type \verb@Object@:
-\begin{verbatim}
-var x: Object = new Rational(1,2);
-\end{verbatim}
-
-\paragraph{Parameterless Methods.}
-%Also unlike in Java, methods in Scala do not necessarily take a
-%parameter list. An example is \verb@toString@; the method is invoked
-%by simply mentioning its name. For instance:
-%\begin{verbatim}
-%val r = new Rational(1,2);
-%System.out.println(r.toString()); // prints``1/2''
-%\end{verbatim}
-Also unlike in Java, methods in Scala do not necessarily take a
-parameter list. An example is the \verb@square@ method below. This
-method is invoked by simply mentioning its name.
-\begin{verbatim}
-class Rational(n: int, d: int) extends Object {
- ... // as before
- def square = Rational(numer*numer, denom*denom);
-}
-val r = new Rational(3,4);
-System.out.println(r.square); // prints``9/16''
-\end{verbatim}
-That is, parameterless methods are accessed just as value fields such
-as \verb@numer@ are. The difference between values and parameterless
-methods lies in their definition. The right-hand side of a value is
-evaluated when the object is created, and the value does not change
-afterwards. A right-hand side of a parameterless method, on the other
-hand, is evaluated each time the method is called. The uniform access
-of fields and parameterless methods gives increased flexibility for
-the implementer of a class. Often, a field in one version of a class
-becomes a computed value in the next version. Uniform access ensures
-that clients do not have to be rewritten because of that change.
-
-\paragraph{Abstract Classes}
-
-Consider the task of writing a class for sets of integer numbers with
-two operations, \verb@incl@ and \verb@contains@. \verb@(s incl x)@
-should return a new set which contains the element \verb@x@ togther
-with all the elements of set \verb@s@. \verb@(s contains x)@ should
-return true if the set \verb@s@ contains the element \verb@x@, and
-should return \verb@false@ otherwise. The interface of such sets is
-given by:
-\begin{verbatim}
-abstract class IntSet {
- def incl(x: int): IntSet;
- def contains(x: int): boolean;
-}
-\end{verbatim}
-\verb@IntSet@ is labeled as an \emph{abstract class}. This has two
-consequences. First, abstract classes may have {\em deferred} members
-which are declared but which do not have an implementation. In our
-case, both \verb@incl@ and \verb@contains@ are such members. Second,
-because an abstract class might have unimplemented members, no objects
-of that class may be created using \verb@new@. By contrast, an
-abstract class may be used as a base class of some other class, which
-implements the deferred members.
-
-\paragraph{Traits.}
-
-Instead of ``\verb@abstract class@ one also often uses the keyword
-\verb@trait@ in Scala. A trait is an abstract class with no state, no
-constructor arguments, and no side effects during object
-initialization. Since \verb@IntSet@'s fall in this category, one can
-alternatively define them as traits:
-\begin{verbatim}
-trait IntSet {
- def incl(x: int): IntSet;
- def contains(x: int): boolean;
-}
-\end{verbatim}
-A trait corresponds to an interface in Java, except
-that a trait can also define implemented methods.
-
-\paragraph{Implementing Abstract Classes}
-
-Let's say, we plan to implement sets as binary trees. There are two
-possible forms of trees. A tree for the empty set, and a tree
-consisting of an integer and two subtrees. Here are their
-implementations.
-
-\begin{verbatim}
-class Empty extends IntSet {
- def contains(x: int): boolean = false;
- def incl(x: int): IntSet = new NonEmpty(x, new Empty, new Empty);
-}
-\end{verbatim}
-
-\begin{verbatim}
-class NonEmpty(elem:int, left:IntSet, right:IntSet) extends IntSet {
- def contains(x: int): boolean =
- if (x < elem) left contains x
- else if (x > elem) right contains x
- else true;
- def incl(x: int): IntSet =
- if (x < elem) new NonEmpty(elem, left incl x, right)
- else if (x > elem) new NonEmpty(elem, left, right incl x)
- else this;
-}
-\end{verbatim}
-Both \verb@Empty@ and \verb@NonEmpty@ extend class
-\verb@IntSet@. This implies that types \verb@Empty@ and
-\verb@NonEmpty@ conform to type \verb@IntSet@ -- a value of type \verb@Empty@ or \verb@NonEmpty@ may be used wherever a value of type \verb@IntSet@ is required.
-
-\exercise Write methods \verb@union@ and \verb@intersection@ to form
-the union and intersection between two sets.
-
-\exercise Add a method
-\begin{verbatim}
-def excl(x: int)
-\end{verbatim}
-to return the given set without the element \verb@x@. To accomplish this,
-it is useful to also implement a test method
-\begin{verbatim}
-def isEmpty: boolean
-\end{verbatim}
-for sets.
-
-\paragraph{Dynamic Binding}
-
-Object-oriented languages (Scala included) use \emph{dynamic dispatch}
-for method invocations. That is, the code invoked for a method call
-depends on the run-time type of the object which contains the method.
-For example, consider the expression \verb@s contains 7@ where
-\verb@s@ is a value of declared type \verb@s: IntSet@. Which code for
-\verb@contains@ is executed depends on the type of value of \verb@s@ at run-time.
-If it is an \verb@Empty@ value, it is the implementation of \verb@contains@ in class \verb@Empty@ that is executed, and analogously for \verb@NonEmpty@ values.
-This behavior is a direct consequence of our substitution model of evaluation.
-For instance,
-\begin{verbatim}
- (new Empty).contains(7)
-
--> $\rewriteby{by replacing {\sl contains} by its body in class {\sl Empty}}$
-
- false
-\end{verbatim}
-Or,
-\begin{verbatim}
- new NonEmpty(7, new Empty, new Empty).contains(1)
-
--> $\rewriteby{by replacing {\sl contains} by its body in class {\sl NonEmpty}}$
-
- if (1 < 7) new Empty contains 1
- else if (1 > 7) new Empty contains 1
- else true
-
--> $\rewriteby{by rewriting the conditional}$
-
- new Empty contains 1
-
--> $\rewriteby{by replacing {\sl contains} by its body in class {\sl Empty}}$
-
- false .
-\end{verbatim}
-
-Dynamic method dispatch is analogous to higher-order function
-calls. In both cases, the identity of code to be executed is known
-only at run-time. This similarity is not just superficial. Indeed,
-Scala represents every function value as an object (see
-Section~\ref{sec:funs-are-objects}).
-
-
-\paragraph{Objects}
-
-In the previous implementation of integer sets, empty sets were
-expressed with \verb@new Empty@; so a new object was created every time
-an empty set value was required. We could have avoided unnecessary
-object creations by defining a value \verb@empty@ once and then using
-this value instead of every occurrence of \verb@new Empty@. E.g.
-\begin{verbatim}
-val empty = new Empty;
-\end{verbatim}
-One problem with this approach is that a value definition such as the
-one above is not a legal top-level definition in Scala; it has to be
-part of another class or object. Also, the definition of class
-\verb@Empty@ now seems a bit of an overkill -- why define a class of objects,
-if we are only interested in a single object of this class? A more
-direct approach is to use an {\em object definition}. Here is
-a more streamlined alternative definition of the empty set:
-\begin{verbatim}
-object empty extends IntSet {
- def contains(x: int): boolean = false;
-
- def incl(x: int): IntSet = new NonEmpty(x, empty, empty);
-}
-\end{verbatim}
-The syntax of an object definition follows the syntax of a class
-definition; it has an optional extends clause as well as an optional
-body. As is the case for classes, the extends clause defines inherited
-members of the object whereas the body defines overriding or new
-members. However, an object definition defines a single object only;
-it is not possible to create other objects with the same structure
-using \verb@new@. Therefore, object definitions also lack constructor
-parameters, which might be present in class definitions.
-
-Object definitions can appear anywhere in a Scala program; including
-at top-level. Since there is no fixed execution order of top-level
-entities in Scala, one might ask exactly when the object defined by an
-object definition is created and initialized. The answer is that the
-object is created the first time one of its members is accessed. This
-strategy is called {\em lazy evaluation}.
-
-\paragraph{Standard Classes}
-
-Scala is a pure object-oriented language. This means that every value
-in Scala can be regarded as an object. In fact, even primitive types
-such as \verb@int@ or \verb@boolean@ are not treated specially. They
-are defined as type aliases of Scala classes in module \verb@Predef@:
-\begin{verbatim}
-type boolean = scala.Boolean;
-type int = scala.Int;
-type long = scala.Long;
-...
-\end{verbatim}
-For efficiency, the compiler usually represents values of type
-\verb@scala.Int@ by 32 bit integers, values of type
-\verb@scala.Boolean@ by Java's booleans, etc. But it converts these
-specialized representations to objects when required, for instance
-when a primitive \verb@int@ value is passed to a function that with a
-parameter of type \verb@Object@. Hence, the special representation of
-primitive values is just an optimization, it does not change the
-meaning of a program.
-
-Here is a specification of class \verb@Boolean@.
-\begin{verbatim}
-package scala;
-trait Boolean {
- def && (def x: Boolean)\=: Boolean;
- def || (def x: Boolean)\>: Boolean;
- def ! \>: Boolean;
-
- def == (x: Boolean)\>: Boolean
- def != (x: Boolean)\>: Boolean
- def < (x: Boolean)\>: Boolean
- def > (x: Boolean)\>: Boolean
- def <= (x: Boolean)\>: Boolean
- def >= (x: Boolean)\>: Boolean
-}
-\end{verbatim}
-Booleans can be defined using only classes and objects, without
-reference to a built-in type of booleans or numbers. A possible
-implementation of class \verb@Boolean@ is given below. This is not
-the actual implementation in the standard Scala library. For
-efficiency reasons the standard implementation is built from built-in
-booleans.
-\begin{verbatim}
-package scala;
-trait Boolean {
- def ifThenElse(def thenpart: Boolean, def elsepart: Boolean)
-
- def && (def x: Boolean)\=: Boolean = ifThenElse(x, false);
- def || (def x: Boolean)\>: Boolean = ifThenElse(true, x);
- def ! \>: Boolean = ifThenElse(false, true);
-
- def == (x: Boolean)\>: Boolean = ifThenElse(x, x.!);
- def != (x: Boolean)\>: Boolean = ifThenElse(x.!, x);
- def < (x: Boolean)\>: Boolean = ifThenElse(false, x);
- def > (x: Boolean)\>: Boolean = ifThenElse(x.!, false);
- def <= (x: Boolean)\>: Boolean = ifThenElse(x, true);
- def >= (x: Boolean)\>: Boolean = ifThenElse(true, x.!);
-}
-object True extends Boolean \={ def ifThenElse(def t: Boolean, def e: Boolean) = t }
-object False extends Boolean \>{ def ifThenElse(def t: Boolean, def e: Boolean) = e }
-\end{verbatim}
-Here is a partial specification of class \verb@Int@.
-
-\begin{verbatim}
-package scala;
-trait Int extends Long {
- def + (that: Double): Double;
- def + (that: Float): Float;
- def + (that: Long): Long;
- def + (that: Int): Int; \=/* analogous for -, *, /, % */
-
- def << (cnt: Int): Int; \>/* analogous for >>, >>> */
-
- def & (that: Long): Long;
- def & (that: Int): Int; \>/* analogous for |, ^ */
-
- def == (that: Double): Boolean;
- def == (that: Float): Boolean;
- def == (that: Long): Boolean; \> /* analogous for !=, <, >, <=, >= */
-}
-\end{verbatim}
-
-Class \verb@Int@ can in principle also be implemented using just
-objects and classes, without reference to a built in type of
-integers. To see how, we consider a slightly simpler problem, namely
-how to implement a type \verb@Nat@ of natural (i.e. non-negative)
-numbers. Here is the definition of a trait \verb@Nat@:
-\begin{verbatim}
-trait Nat {
- def isZero: Boolean;
- def predecessor: Nat;
- def successor: Nat;
- def + (that: Nat): Nat;
- def - (that: Nat): Nat;
-}
-\end{verbatim}
-To implement the operations of class \verb@Nat@, we define a subobject
-\verb@Zero@ and a subclass \verb@Succ@ (for successor). Each number
-\verb@N@ is represented as \verb@N@ applications of the \verb@Succ@
-constructor to \verb@Zero@:
-\[
-\underbrace{\mbox{\sl new Succ( ... new Succ}}_{\mbox{$N$ times}}\mbox{\sl (Zero) ... )}
-\]
-The implementation of the \verb@Zero@ object is straightforward:
-\begin{verbatim}
-object Zero extends Nat {
- def isZero: Boolean = true;
- def predecessor: Nat = error("negative number");
- def successor: Nat = new Succ(Zero);
- def + (that: Nat): Nat = that;
- def - (that: Nat): Nat = if (that.isZero) Zero else error("negative number")
-}
-\end{verbatim}
-
-The implementation of the predecessor and subtraction functions on
-\verb@Zero@ contains a call to the predefined \verb@error@
-function. This function aborts the program with the given error
-message.
-
-Here is the implementation of the successor class:
-\begin{verbatim}
-class Succ(x: Nat) extends Nat {
- def isZero: Boolean = false;
- def predecessor: Nat = x;
- def successor: Nat = new Succ(this);
- def + (that: Nat): Nat = x.+(that.successor);
- def - (that: Nat): Nat = x.-(that.predecessor)
-}
-\end{verbatim}
-Note the implementation of method \verb@successor@. To create the
-successor of a number, we need to pass the object itself as an
-argument to the \verb@Succ@ constructor. The object itself is
-referenced by the reserved name \verb@this@.
-
-The implementations of \verb@+@ and \verb@-@ each contain a recursive
-call with the constructor argument as receiver. The recursion will
-terminate once the receiver is the \verb@Zero@ object (which is
-guaranteed to happen eventually from the way numbers are formed).
-
-\exercise Write an implementation \verb@Integer@ of integer numbers
-The implementation should support all operations of class \verb@Nat@
-while adding two methods
-\begin{verbatim}
-def isPositive: Boolean
-def negate: Integer
-\end{verbatim}
-The first method should return \verb@true@ if the number is positive. The second method should negate the number.
-Do not use any of Scala's standard numeric classes in your
-implementation. (Hint: There are two possible ways to implement
-\verb@Integer@. One can either make use the existing implementation of
-\verb@Nat@, representing an integer as a natural number and a sign.
-Or one can generalize the given implementation of \verb@Nat@ to
-\verb@Integer@, using the three subclasses \verb@Zero@ for 0,
-\verb@Succ@ for positive numbers and \verb@Pred@ for negative numbers.)
-
-
-
-\paragraph{Language Elements Introduced In This Chapter}
-
-\paragraph{Types:}
-\begin{verbatim}
-Type \= = ... | ident
-\end{verbatim}
-
-Types can now be arbitrary identifiers which represent classes.
-
-\paragraph{Expressions:}
-\begin{verbatim}
-Expr \= = ... | Expr `.' ident | new Expr | this
-\end{verbatim}
-
-An expression can now be an object creation, or
-a selection \verb@E.m@ of a member \verb@m@
-from an object-valued expression \verb@E@, or it can be the reserved name \verb@this@.
-
-\paragraph{Definitions and Declarations:}
-\begin{verbatim}
-Def \= = \=FunDef | ValDef | ClassDef | TraitDef | ObjectDef
-ClassDef \> = \>[abstract] class ident [`(' [Parameters] `)']
- \> \>[extends Expr] [`{' {TemplateDef} `}']
-TraitDef \> = \>trait ident [extends Expr] [`{' {TemplateDef} `}']
-ObjectDef \> = \>object ident [extends Expr] [`{' {ObjectDef} `}']
-TemplateDef \> = \>[Modifier] (Def | Dcl)
-ObjectDef \> = \>[Modifier] Def
-Modifier \> = \>private | override
-Dcl \> = \>FunDcl | ValDcl
-FunDcl \> = \>def ident {`(' [Parameters] `)'} `:' Type
-ValDcl \> = \>val ident `:' Type
-\end{verbatim}
-
-A definition can now be a class, trait or object definition such as
-\begin{verbatim}
-class C(params) extends B { defs }
-trait T extends B { defs }
-object O extends B { defs }
-\end{verbatim}
-The definitions \verb@defs@ in a class, trait or object may be
-preceded by modifiers \verb@private@ or \verb@override@.
-
-Abstract classes and traits may also contain declarations. These
-introduce {\em deferred} functions or values with their types, but do
-not give an implementation. Deferred members have to be implemented in
-subclasses before objects of an abstract class or trait can be created.
-
-\chapter{Case Classes and Pattern Matching}
-
-Say, we want to write an interpreter for arithmetic expressions. To
-keep things simple initially, we restrict ourselves to just numbers
-and \verb@+@ operations. Such expressions can be represented as a class hierarchy, with an abstract base class \verb@Expr@ as the root, and two subclasses \verb@Number@ and
-\verb@Sum@. Then, an expression \verb@1 + (3 + 7)@ would be represented as
-\begin{verbatim}
-new Sum(new Number(1), new Sum(new Number(3), new Number(7)))
-\end{verbatim}
-Now, an evaluator of an expression like this needs to know of what
-form it is (either \verb@Sum@ or \verb@Number@) and also needs to
-access the components of the expression. The following
-implementation provides all necessary methods.
-\begin{verbatim}
-abstract class Expr {
- def isNumber: boolean;
- def isSum: boolean;
- def numValue: int;
- def leftOp: Expr;
- def rightOp: Expr;
-}
-\end{verbatim}
-\begin{verbatim}
-class Number(n: int) extends Expr {
- def isNumber: boolean = true;
- def isSum: boolean = false;
- def numValue: int = n;
- def leftOp: Expr = error("Number.leftOp");
- def rightOp: Expr = error("Number.rightOp");
-}
-\end{verbatim}
-\begin{verbatim}
-class Sum(e1: Expr, e2: Expr) extends Expr {
- def isNumber: boolean = false;
- def isSum: boolean = true;
- def numValue: int = error("Sum.numValue");
- def leftOp: Expr = e1;
- def rightOp: Expr = e2;}
-\end{verbatim}
-With these classification and access methods, writing an evaluator function is simple:
-\begin{verbatim}
-def eval(e: Expr): int = {
- if (e.isNumber) e.numValue
- else if (e.isSum) eval(e.leftOp) + eval(e.rightOp)
- else error("unrecognized expression kind")
-}
-\end{verbatim}
-However, defining all these methods in classes \verb@Sum@ and
-\verb@Number@ is rather tedious. Furthermore, the problem becomes worse
-when we want to add new forms of expressions. For instance, consider
-adding a new expression form
-\verb@Prod@ for products. Not only do we have to implement a new class \verb@Prod@, with all previous classification and access methods; we also have to introduce a
-new abstract method \verb@isProduct@ in class \verb@Expr@ and
-implement that method in subclasses \verb@Number@, \verb@Sum@, and
-\verb@Prod@. Having to modify existing code when a system grows is always problematic, since it introduces versioning and maintenance problems.
-
-The promise of object-oriented programming is that such modifications
-should be unnecessary, because they can be avoided by re-using
-existing, unmodified code through inheritance. Indeed, a more
-object-oriented decomposition of our problem solves the problem. The
-idea is to make the ``high-level'' operation \verb@eval@ a method of
-each expression class, instead of implementing it as a function
-outside the expression class hierarchy, as we have done
-before. Because \verb@eval@ is now a member of all expression nodes,
-all classification and access methods become superfluous, and the implementation is simplified considerably:
-\begin{verbatim}
-abstract class Expr {
- def eval: int;
-}
-class Number(n: int) extends Expr {
- def eval: int = n;
-}
-class Sum(e1: Expr, e2: Expr) extends Expr {
- def eval: int = e1.eval + e2.eval;
-}
-\end{verbatim}
-Furthermore, adding a new \verb@Prod@ class does not entail any changes to existing code:
-\begin{verbatim}
-class Prod(e1: Expr, e2: Expr) extends Expr {
- def eval: int = e1.eval * e2.eval;
-}
-\end{verbatim}
-
-The conclusion we can draw from this example is that object-oriented
-decomposition is the technique of choice for constructing systems that
-should be extensible with new types of data. But there is also another
-possible way we might want to extend the expression example. We might
-want to add new {\em operations} on expressions. For instance, we might
-want to add an operation that pretty-prints an expression tree to standard output.
-
-If we have defined all classification and access methods, such an
-operation can easily be written as an external function. Here is an
-implementation:
-\begin{verbatim}
-def print(e: Expr): unit =
- if (e.isNumber) System.out.print(e.numValue)
- else if (e.isSum) {
- System.out.print("(");
- print(e.leftOp);
- System.out.print("+");
- print(e.rightOp);
- System.out.print(")");
- } else error("unrecognized expression kind");
-\end{verbatim}
-However, if we had opted for an object-oriented decomposition of
-expressions, we would need to add a new \verb@print@ method
-to each class:
-\begin{verbatim}
-abstract class Expr {
- def eval: int;
- def print: unit;
-}
-class Number(n: int) extends Expr {
- def eval: int = n;
- def print: unit = System.out.print(n);
-}
-class Sum(e1: Expr, e2: Expr) extends Expr {
- def eval: int = e1.eval + e2.eval;
- def print: unit = {
- System.out.print("(");
- print(e1);
- System.out.print("+");
- print(e2);
- System.out.print(")");
-}
-\end{verbatim}
-Hence, classical object-oriented decomposition requires modification
-of all existing classes when a system is extended with new operations.
-
-As yet another way we might want to extend the interpreter, consider
-expression simplification. For instance, we might want to write a
-function which rewrites expressions of the form
-\verb@a * b + a * c@ to \verb@a * (b + c)@. This operation requires inspection of
-more than a single node of the expression tree at the same
-time. Hence, it cannot be implemented by a method in each expression
-kind, unless that method can also inspect other nodes. So we are
-forced to have classification and access methods in this case. This
-seems to bring us back to square one, with all the problems of
-verbosity and extensibility.
-
-Taking a closer look, one observers that the only purpose of the
-classification and access functions is to {\em reverse} the data
-construction process. They let us determine, first, which sub-class
-of an abstract base class was used and, second, what were the
-constructor arguments. Since this situation is quite common, Scala has
-a way to automate it with case classes.
-
-\paragraph{Case Classes.}
-A {\em case class} is defined like a normal class, except that the definition
-is prefixed with the modifier \verb@case@. For instance, the definitions
-\begin{verbatim}
-abstract class Expr;
-case class Number(n: int) extends Expr;
-case class Sum(e1: Expr, e2: Expr) extends Expr;
-\end{verbatim}
-introduce \verb@Number@ and \verb@Sum@ as case classes.
-The \verb@case@ modifier in front of a class definition has the following effects.
-\begin{enumerate}
-\item Case classes implicitly come with a constructor function, with the same name as the class. In our example, the two functions
-\begin{verbatim}
-def Number(n: int) = new Number(n);
-def Sum(e1: Expr, e2: Expr) = new Sum(e1, e2);
-\end{verbatim}
-would be added. Hence, one can now construct expression trees a bit more concisely, as in
-\begin{verbatim}
-Sum(Sum(Number(1), Number(2)), Number(3))
-\end{verbatim}
-\item Case classes implicity come with implementations of methods
-\verb@toString@, \verb@equals@ and \verb@hashCode@, which override the
-methods with the same name in class \verb@Object@. The implementation
-of these methods takes in each case the structure of a member of a
-case class into account. The \verb@toString@ method represents an
-expression tree the way it was constructed. So,
-\begin{verbatim}
-Sum(Sum(Number(1), Number(2)), Number(3))
-\end{verbatim}
-would be converted to exactly that string, whereas he default
-implementation in class \verb@Object@ would return a string consisting
-of the outermost constructor name \verb@Sum@ and a number. The
-\verb@equals@ methods treats two case members of a case class as equal
-if they have been constructed with the same constructor and with
-arguments which are themselves pairwise equal. This also affects the
-implementation of \verb@==@ and \verb@!=@, which are implemented in
-terms of \verb@equals@ in Scala. So,
-\begin{verbatim}
-Sum(Number(1), Number(2)) == Sum(Number(1), Number(2))
-\end{verbatim}
-will yield \verb@true@. If \verb@Sum@ or \verb@Number@ were not case
-classes, the same expression would be \verb@false@, since the standard
-implementation of \verb@equals@ in class \verb@Object@ always treats
-objects created by different constructor calls as being different.
-The \verb@hashCode@ method follows the same principle as other two
-methods. It computes a hash code from the case class constructor name
-and the hash codes of the constructor arguments, instead of from the object's
-address, which is what the as the default implementation of \verb@hashCode@ does.
-\item
-Case classes implicity come with nullary accessor methods which
-retrieve the constructor arguments.
-In our example, \verb@Number@ would obtain an accessor method
-\begin{verbatim}
-def n: int
-\end{verbatim}
-which returns the constructor parameter \verb@n@, whereas \verb@Sum@ would obtain two accessor methods
-\begin{verbatim}
-def e1: Expr, e2: Expr;
-\end{verbatim}
-Hence, if for a value \verb@s@ of type \verb@Sum@, say, one can now
-write \verb@s.e1@, to access the left operand. However, for a value
-\verb@e@ of type \verb@Expr@, the term \verb@e.e1@ would be illegal
-since \verb@e1@ is defined in \verb@Sum@; it is not a member of the
-base class \verb@Expr@.
-So, how do we determine the constructor and access constructor
-arguments for values whose static type is the base class \verb@Expr@?
-This is solved by the fourth and final particularity of case classes.
-\item
-Case classes allow the constructions of {\em patterns} which refer to
-the case class constructor.
-\end{enumerate}
-
-\paragraph{Pattern Matching.}
-
-Pattern matching is a generalization of C or Java's \verb@switch@
-statement to class hierarchies. Instead of a \verb@switch@ statement,
-there is a standard method \verb@match@, which is defined in Scala's
-root class \verb@Any@, and therefore is available for all objects.
-The \verb@match@ method takes as argument a number of cases.
-For instance, here is an implementation of \verb@eval@ using
-pattern matching.
-\begin{verbatim}
-def eval(e: Expr): int = e match {
- case Number(x) => x
- case Sum(l, r) => eval(l) + eval(r)
-}
-\end{verbatim}
-In this example, there are two cases. Each case associates a pattern
-with an expression. Patterns are matched against the selector
-values \verb@e@. The first pattern in our example,
-\verb@Number(n)@, matches all values of the form \verb@Number(v)@,
-where \verb@v@ is an arbitrary value. In that case, the {\em pattern
-variable} \verb@n@ is bound to the value \verb@v@. Similarly, the
-pattern \verb@Sum(l, r)@ matches all selector values of form
-\verb@Sum(v$_1$, v$_2$)@ and binds the pattern variables \verb@l@ and \verb@r@
-to \verb@v$_1$@ and \verb@v$_2$@, respectively.
-
-In general, patterns are built from
-\begin{itemize}
-\item Case class constructors, e.g. \verb@Number@, \verb@Sum@, whose arguments
- are again patterns,
-\item pattern variables, e.g. \verb@n@, \verb@e1@, \verb@e2@,
-\item the ``wildcard'' pattern \verb@_@,
-\item constants, e.g. \verb@1@, \verb@true@, "abc", \verb@MAXINT@.
-\end{itemize}
-Pattern variables always start with a lower-case letter, so that they
-can be distinguished from constant identifiers, which start with an
-upper case letter. The only exceptions to that rule are the reserved
-words \verb@null@, \verb@true@, \verb@false@, which are treated as constants.
-Each variable name may occur only once in a pattern. For instance,
-\verb@Sum(x, x)@ would be illegal as a pattern, since \verb@x@ occurs
-twice in it.
-
-\paragraph{Meaning of Pattern Matching.}
-A pattern matching expression
-\begin{verbatim}
-e.match { case p$_1$ => e$_1$ ... case p$_n$ => e$_n$ }
-\end{verbatim}
-matches the patterns $p_1 \commadots p_n$ in the order they
-are written against the selector value \verb@e@.
-\begin{itemize}
-\item
-A constructor pattern $C(p_1 \commadots p_n)$ matches all values that
-are of type \verb@C@ (or a subtype thereof) and that have been constructed with
-\verb@C@-arguments matching patterns $p_1 \commadots p_n$.
-\item
-A variable pattern \verb@x@ matches any value and binds the variable
-name to that value.
-\item
-The wildcard pattern `\verb@_@' matches any value but does not bind a name to that value.
-\item A constant pattern \verb@C@ matches a value which is
-equal (in terms of \verb@==@) to \verb@C@.
-\end{itemize}
-The pattern matching expression rewrites to the right-hand-side of the
-first case whose pattern matches the selector value. References to
-pattern variables are replaced by corresponding constructor arguments.
-If none of the patterns matches, the pattern matching expression is
-aborted with a \verb@MatchError@ exception.
-
-\example Our substitution model of program evaluation extends quite naturally to pattern matching, For instance, here is how \verb@eval@ applied to a simple expression is re-written:
-\begin{verbatim}
- \= eval(Sum(Number(1), Number(2)))
-
--> \> $\mbox{\tab\tab\rm(by rewriting the application)}$
-
- \> Sum(Number(1), Number(2)) match {
- \> case Number(n) => n
- \> case Sum(e1, e2) => eval(e1) + eval(e2)
- \> }
-
--> \> $\mbox{\tab\tab\rm(by rewriting the pattern match)}$
-
- \> eval(Number(1)) + eval(Number(2))
-
--> \> $\mbox{\tab\tab\rm(by rewriting the first application)}$
-
- \> Number(1) match {
- \> case Number(n) => n
- \> case Sum(e1, e2) => eval(e1) + eval(e2)
- \> } + eval(Number(2))
-
--> \> $\mbox{\tab\tab\rm(by rewriting the pattern match)}$
-
- \> 1 + eval(Number(2))
-
-->$^*$ \> 1 + 2 -> 3
-\end{verbatim}
-
-\paragraph{Pattern Matching and Methods.} In the previous example, we have used pattern
-matching in a function which was defined outside the class hierarchy
-over which it matches. Of course, it is also possible to define a
-pattern matching function in that class hierarchy itself. For
-instance, we could have defined
-\verb@eval@ is a method of the base class \verb@Expr@, and still have used pattern matching in its implementation:
-\begin{verbatim}
-abstract class Expr {
- def eval: int = this match {
- case Number(n) => n
- case Sum(e1, e2) => e1.eval + e2.eval
- }
-}
-\end{verbatim}
-
-\exercise
-Consider the following three classes representing trees of integers.
-These classes can be seen as an alternative representation of \verb@IntSet@:
-\begin{verbatim}
-trait IntTree;
-case class Empty extends IntTree;
-case class Node(elem: int, left: IntTree, right: IntTree) extends IntTree;
-\end{verbatim}
-Complete the following implementations of function \verb@contains@ and \verb@insert@ for
-\verb@IntTree@'s.
-\begin{verbatim}
-def contains(t: IntTree, v: int): boolean = t match { ...
- ...
-}
-def insert(t: IntTree, v: int): IntTree = t match { ...
- ...
-}
-\end{verbatim}
-
-\subsection*{Tuples}
-
-Sometimes, a function needs to return more than one result. For
-instance, take the function \verb@divmod@ which returns the quotient
-and rest of two given integer arguments. Of course, one can
-define a class to hold the two results of \verb@divmod@, as in:
-\begin{verbatim}
-case class TwoInts(first: int, second: int);
-
-def divmod(x: int, y: int): TwoInts = new TwoInts(x / y, x % y)
-\end{verbatim}
-However, having to define a new class for every possible pair of
-result types is very tedious. It should also be unneccessary because
-all such classes have exactly the same structure. In Scala, the
-repetition can be avoided by defining a {\em generic class}:
-\begin{verbatim}
-case class Pair[+a, +b](first: a, second: b);
-
-def divmod(x: int, y: int): Pair[int, int] = new Pair[Int, Int](x / y, x % y)
-\end{verbatim}
-In this example, \verb@[a, b]@ are {\em type parameters} of class
-\verb@Pair@. In a \verb@Pair@ type, these parameters are replaced by
-concrete types. For instance, \verb@Pair[int, String]@ represents the
-type of pairs with \verb@int@ and \verb@String@ elements.
-
-Type arguments can be omitted in constructors, if the correct type can
-be inferred from the other constructor arguments or the constructor's
-expected result type. In our example, we could have omitted the type
-arguments in the body of \verb@divmod@, because they can be deduced
-from the two value parameters of type \verb@int@:
-\begin{verbatim}
-def divmod(x: int, y: int): Pair[int, int] = new Pair(x / y, x % y)
-\end{verbatim}
-Type parameters are never used in patterns. For instance, here is an
-expression in which \verb@divmod@'s result is decomposed:
-\begin{verbatim}
-divmod(x, y) match {
- case Pair(n, d) => System.out.println("quotient: " + n + ", rest: " + d);
-}
-\end{verbatim}
-The type parameters in class \verb@Pair@ are each prefixed by a
-\verb@+@ sign. This indicates that \verb@Pair@s are {\em
-covariant}. That is, if types \verb@T$_1$@ and \verb@T$_2$@ are
-subtypes of types \verb@S$_1$@ and \verb@S$_2$@, then
-\verb@Pair[T$_1$, T$_2$]@ is a subtype of
-\verb@Pair[S$_1$, S$_2$]@. For instance, \verb@Pair[String, int]@ is a
-subtype of \verb@Pair[Object, long]@. If the \verb@+@-annotation was
-missing, the type constructor would be treated as being
-non-variant. That is, pairs with different element types would never
-be in a subtype relation.
-Besides, \verb@+@, there is also a prefix
-\verb@-@ for contra-variant type constructors.
-The precise rules that
-for variance annotations are given in Chapter~\ref{sec:variance}.
-
-The idea of pairs is generalized in Scala to tuples of greater arity.
-There is a predefined case class \verb@Tuple$_n$@ for every \verb@n@
-from \verb@2@ to \verb@9@ in Scala's standard library. The
-definitions all follow the template
-\begin{verbatim}
-case class Tuple$_n$[+a$_1$, ..., +a$_n$](_1: a$_1$, ..., _n: a$_n$);
-\end{verbatim}
-Class \verb@Pair@ (as well as class \verb@Triple@) are also
-predefined, but not as classes of their own. Instead
-\verb@Pair@ is an alias of \verb@Tuple2@ and \verb@Triple@ is an
-alias of \verb@Tuple3@.
-
-\chapter{Lists}
-
-The list is an important data structure in many Scala programs.
-A list with elements \verb@x$_1$, ..., x$_n$@ is written
-\verb@List(x$_1$, ..., x$_n$)@. Examples are:
-\begin{verbatim}
-val fruit \= = List("apples", "oranges", "pears");
-val nums \> = List(1, 2, 3, 4);
-val diag3 \> = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1));
-val empty \> = List();
-\end{verbatim}
-Lists are similar to arrays in languages such as C or Java, but there
-are also three important differences. First, lists are immutable. That
-is, elements of a list can not be changed by assignment. Second,
-lists have a recursive structure, whereas arrays are flat. Third,
-lists support a much richer set of operations than arrays usually do.
-
-\paragraph{The list type.}
-Like arrays, lists are {\em homogeneous}. That is, the elements of a
-list all have the same type. The type of a list with elements of type
-\verb@T@ is written \verb@List[T]@. (Compare to \verb@[]T@ for the
-type of arrays of type \verb@T@ in C or Java.). Therefore, the
-definitions of list values above can be annotated with types as
-follows.
-\begin{verbatim}
-val fruit \= : List[String] \= = List("apples", "oranges", "pears");
-val nums \> : List[int] \> = List(1, 2, 3, 4);
-val diag3 \> : List[List[int]] \> = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1));
-val empty \> : List[int] \> = List();
-\end{verbatim}
-
-\paragraph{List constructors.}
-All lists are built from two more fundamental constructors, \verb@Nil@
-and \verb@::@ (pronounced ``cons''). \verb@Nil@ represents an empty
-list. The infix operator \verb@::@ expresses list extension. That is,
-\verb@x :: xs@ represents a list whose first element is \verb@x@,
-which is followed by (the elements of) list \verb@xs@. Hence, the
-list values above could also have been defined as follows (in fact
-their previous definition is simply syntactic sugar for the definitions below).
-\begin{verbatim}
-val fruit \= = "apples" :: ("oranges" :: ("pears" :: Nil));
-val nums \> = 1 :: (2 :: (3 :: (4 :: Nil)));
-val diag3 \> = \= (1 :: (0 :: (0 :: Nil))) ::
- \> \> (0 :: (1 :: (0 :: Nil))) ::
- \> \> (0 :: (0 :: (1 :: Nil))) :: Nil;
-val empty \> = Nil;
-\end{verbatim}
-The `\verb@::@' operation associates to the right: \verb@A :: B :: C@ is
-interpreted as \verb@A :: (B :: C)@. Therefore, we can drop the
-parentheses in the definitions above. For instance, we can write
-shorter
-\begin{verbatim}
-val nums = 1 :: 2 :: 3 :: 4 :: Nil;
-\end{verbatim}
-
-\paragraph{Basic operations on lists.}
-All operations on lists can be expressed in terms of the following three:
-
-\begin{tabular}{ll}
-\verb@head@ & returns the first element of a list,\\
-\verb@tail@ & returns the list consisting of all elements except the\\
-first element,
-\verb@isEmpty@ & returns \verb@true@ iff the list is empty
-\end{tabular}
-
-These operations are defined as methods of list objects. So we invoke
-them by selecting from the list that's operated on. Examples:
-\begin{verbatim}
-empty.isEmpty \= = true
-fruit.isEmpty \> = false
-fruit.head \> = "apples"
-fruit.tail.head \> = "oranges"
-diag3.head \> = List(1, 0, 0)
-\end{verbatim}
-Both \verb@head@ and \verb@tail@ are only defined for non-empty lists.
-When selected from an empty list, they cause an error instead.
-
-As an example of how lists can be processed, consider sorting the
-elements of a list of numbers into ascending order. One simple way to
-do so is {\em insertion sort}, which works as follows: To sort a
-non-empty list with first element \verb@x@ and rest \verb@xs@, sort
-the remainder \verb@xs@ and insert the element \verb@x@ at the right
-position in the result. Sorting an empty list will of course yield the
-empty list. Expressed as Scala code:
-\begin{verbatim}
-def isort(xs: List[int]): List[int] =
- if (xs.isEmpty) Nil
- else insert(xs.head, isort(xs.tail))
-\end{verbatim}
-
-\exercise Provide an implementation of the missing function
-\verb@insert@.
-
-\paragraph{List patterns.} In fact, \verb@::@ is
-defined defined as a case class in Scala's standard library. Hence, it
-is possible to decompose lists by pattern matching, using patterns
-composed from the \verb@Nil@ and \verb@::@ constructors. For instance,
-\verb@isort@ can be written alternatively as follows.
-\begin{verbatim}
-def isort(xs: List[int]): List[int] = xs match {
- case List() => List()
- case x :: xs1 => insert(x, isort(xs1))
-}
-\end{verbatim}
-where
-\begin{verbatim}
-def insert(x: int, xs: List[int]): List[int] = xs match {
- case List() => List(x)
- case y :: ys => if (x <= y) x :: xs else y :: insert(x, ys)
-}
-\end{verbatim}
-
-\paragraph{Polymorphic functions.} Consider the problem of writing a
- function \verb@concat@, which takes a list of element lists as
- arguments. The result of \verb@concat@ should be the concatenation of all
- element lists into a single list.
-
-When trying to define such a function, we observe that we need to give
-a type for the list elements:
-\begin{verbatim}
-def concat(xss: List[List[ ?? ]]): List[ ?? ] = ...
-\end{verbatim}
-Clearly, one could replace \verb@??@ by \verb@int@, say, to obtain a
-function \verb@concat@ that works on lists of lists of integers. But then the
-same function could not be applied to other kinds of lists. This is a
-pity, since clearly the same algorithm of list concatenation can work
-for lists of any element type. Parameterization lets us generalize
-from a specific instance of a problem to a more general one. So far,
-we have used parameterization only for values, but it is available
-also for types. To arrive at a general version of \verb@concat@, we
-equip it with a type parameter.
-\begin{verbatim}
-def concat[a](xs: List[List[a]]): List[a] = xs match {
- case List() => xs
- case List() :: yss => concat[a](yss)
- case (x :: xs) :: yss => x :: concat[a](xs :: yss)
-}
-\end{verbatim}
-Type parameters are arbitrary names; they are enclosed in brackets
-instead of parentheses, so that they can be easily distinguished from
-value parameters. Functions like \verb@concat@ that take type
-parameters are called {\em polymorphic}. The term comes from the
-Greek, where it means ``having many forms''.
-
-To apply \verb@concat@, we pass type parameters as well as value
-parameters to it. For instance,
-\begin{verbatim}
-val diag3 = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1));
-concat[int](diag3)
-\end{verbatim}
-yields \verb@List(1, 0, 0, 0, 1, 0, 0, 0, 1)@.
-
-\paragraph{Local Type Inference.}
-Passing type parameters such as \verb@[int]@ all the time can become
-tedious in applications where polymorphic functions are used a
-lot. Quite often, the information in a type parameter is redundant,
-because the correct parameter type can also be determined by
-inspecting the function's value parameters or expected result type.
-Taking \verb@concat[int](diag3)@ function as an example, we know that
-its value parameter is of type \verb@List[List[int]]@, so we can
-deduce that the type parameter must be \verb@int@. Scala has a
-fairly powerful type inferencer which allows one to omit type
-parameters to polymorphic functions and constructors in situations
-like these. In the example above, the \verb@int@ type parameter would
-have been inferred if it was not given explicitly. In fact, the same
-principle applies in the definition of the value \verb@diag3@.
-Here, type parameters have been inferred for the four calls of
-\verb@List@.
-
-\paragraph{Definition of class \verb@List@}
-
-Lists are not built in in Scala; they are defined by an abstract class
-\verb@List@, which comes with two subclasses for \verb@::@ and \verb@Nil@.
-In the following we present a tour through class \verb@List@.
-\begin{verbatim}
-package scala;
-abstract class List[+a] {
-\end{verbatim}
-\verb@List@ is an abstract class, so one cannot define elements by
-calling the empty \verb@List@ constructor (e.g. by
-\verb@new List@). The class has a type parameter \verb@a@. It is
-co-variant in this parameter, which means that
-\verb@List[S] <: List[T]@ for all types \verb@S@ and \verb@T@ such that
-\verb@S <: T@. The class is situated in the package
-\verb@scala@. This is a package containing the most important standard
-classes of Scala. \verb@List@ defines a number of methods, which are
-explained in the following.
-
-First, there are the three basic functions \verb@isEmpty@,
-\verb@head@, \verb@tail@. Their implementation in terms of pattern
-matching is straightforward:
-\begin{verbatim}
-def isEmpty: boolean = match {
- case Nil => true
- case x :: xs => false
-}
-def head: a = match {
- case Nil => error("Nil.head")
- case x :: xs => x
-}
-def tail: List[a] = match {
- case Nil => error("Nil.tail")
- case x :: xs => x
-}
-\end{verbatim}
-
-The next function computes the length of a list.
-\begin{verbatim}
-def length = match {
- case Nil => 0
- case x :: xs => 1 + xs.length
-}
-\end{verbatim}
-
-\exercise Design a tail-recursive version of \verb@length@.
-
-The next two functions are the complements of \verb@head@ and
-\verb@tail@.
-\begin{verbatim}
-def last: a;
-def init: List[a];
-\end{verbatim}
-\verb@xs.last@ returns the last element of list \verb@xs@, whereas
-\verb@xs.init@ returns all elements of \verb@xs@ except the last.
-Both functions have to traverse the entire list, and are thus less
-efficient than their \verb@head@ and \verb@tail@ analogues.
-Here is the implementation of \verb@last@.
-\begin{verbatim}
-def last: a = match {
- case Nil \==> error("Nil.last")
- case x :: Nil \>=> x
- case x :: xs \>=> xs.last
-}
-\end{verbatim}
-The implementation of \verb@init@ is analogous.
-
-The next three functions return a prefix of the list, or a suffix, or
-both.
-\begin{verbatim}
-def take(n: int): List[a] =
- if (n == 0 || isEmpty) Nil else head :: tail.take(n-1);
-
-def drop(n: int): List[a] =
- if (n == 0 || isEmpty) this else tail.drop(n-1);
-
-def split(n: int): Pair[List[a], List[a]] =
- if (n == 0 || isEmpty) Pair(Nil, this)
- else tail.split(n - 1) match { case Pair(xs, ys) => (head :: xs, ys) }
-\end{verbatim}
-\verb@(xs take n)@ returns the first \verb@n@ elements of list
-\verb@xs@, or the whole list, if its length is smaller than \verb@n@.
-\verb@(xs drop n)@ returns all elements of \verb@xs@ except the
-\verb@n@ first ones. Finally, \verb@(xs split n)@ returns a pair
-consisting of the lists resulting from \verb@xs take n@ and
-\verb@xs drop n@, but the call is more efficient than performing the
-two calls separately.
-
-The next function returns an element at a given index in a list.
-It is thus analogous to array subscripting. Indices start at 0.
-\begin{verbatim}
-def at(n: int): a = drop(n).head;
-\end{verbatim}
-
-With \verb@take@ and \verb@drop@, we can extract sublists consisting
-of consecutive elements of the original list. To extract the sublist
-$xs_m \commadots xs_{n-1}$ of a list \verb@xs@, use:
-
-\begin{verbatim}
-xs.drop(m).take(n - m)
-\end{verbatim}
-
-The next function combines two lists into a list of pairs.
-Given two lists
-\begin{verbatim}
-xs = List(x$_1$, ..., x$_n$) $\mbox{\rm, and}$
-ys = List(y$_1$, ..., y$_n$) ,
-\end{verbatim}
-\verb@xs zip ys@ constructs the list \verb@Pair(x$_1$, y$_1$), ..., Pair(x$_n$, y$_n$)@.
-If the two lists have different lengths, the longer one of the two is
-truncated. Here is the definition of \verb@zip@ -- note that it is a
-polymorphic method.
-\begin{verbatim}
-def zip[b](that: List[b]): List[Pair[a,b]] =
- if (this.isEmpty || that.isEmpty) Nil
- else Pair(this.head, that.head) :: (this.tail zip that.tail);
-\end{verbatim}
-
-Like any infix operator, \verb@::@
-is also implemented as a method of an object. In this case, the object
-is the list that is extended. This is possible, because operators
-ending with a `\verb@:@' character are treated specially in Scala.
-All such operators are treated as methods of their right operand. E.g.,
-\begin{verbatim}
- x :: y = y.::(x) \=$\mbox{\rm whereas}$ x + y = x.+(y)
-\end{verbatim}
-Note, however, that operands of a binary operation are in each case
-evaluated from left to right. So, if \verb@D@ and \verb@E@ are
-expressions with possible side-effects, \verb@D :: E@ is translated to
-\verb@{val x = D; E.::(x)}@ in order to maintain the left-to-right
-order of operand evaluation.
-
-Another difference between operators ending in a `\verb@:@' and other
-operators concerns their associativity. Operators ending in
-`\verb@:@' are right-associative, whereas other operators are
-left-associative. E.g.,
-\begin{verbatim}
- x :: y :: z = x :: (y :: z) \=$\mbox{\rm whereas}$ x + y + z = (x + y) + z
-\end{verbatim}
-The definition of \verb@::@ as a method in
-class \verb@List@ is as follows:
-\begin{verbatim}
-def ::[b >: a](x: b): List[b] = new scala.::(x, this);
-\end{verbatim}
-Note that \verb@::@ is defined for all elements \verb@x@ of type
-\verb@B@ and lists of type \verb@List[A]@ such that the type \verb@B@
-of \verb@x@ is a supertype of the list's element type \verb@A@. The result
-is in this case a list of \verb@B@'s. This
-is expressed by the type parameter \verb@b@ with lower bound \verb@a@
-in the signature of \verb@::@.
-
-An operation similar to \verb@::@ is list concatenation, written
-`\verb@:::@'. The result of \verb@(xs ::: ys)@ is a list consisting of
-all elements of \verb@xs@, followed by all elements of \verb@ys@.
-Because it ends in a colon, \verb@:::@ is right-associative and is
-considered as a method of its right-hand operand. Therefore,
-\begin{verbatim}
-xs ::: ys ::: zs \= = xs ::: (ys ::: zs)
- \> = zs.:::(ys).:::(xs)
-\end{verbatim}
-Here is the implementation of the \verb@:::@ method:
-\begin{verbatim}
- def :::[b >: a](prefix: List[b]): List[b] = prefix match {
- case Nil => this
- case p :: ps => this.:::(ps).::(p)
- }
-\end{verbatim}
-
-\paragraph{Example: Reverse.} As another example of how to program with
-lists consider a list reversal. There is a method \verb@reverse@ in
-\verb@List@ to that effect, but let's implement it as a function
-outside the class. Here is a possible implementation of
-\verb@reverse@:
-\begin{verbatim}
-def reverse[a](xs: List[a]): List[a] = xs match {
- case List() => List()
- case x :: xs => reverse(xs) ::: List(x)
-}
-\end{verbatim}
-The implementation is quite simple. However, it is not very efficient.
-Indeed, one concatenation is executed for every element in the
-list. List concatenation takes time proportional to the length
-of its first operand. Therefore, the complexity of \verb@reverse(xs)@ is
-\[
-n + (n - 1) + ... + 1 = n(n+1)/2
-\]
-where $n$ is the length of \verb@xs@. Can \verb@reverse@ be
-implemented more efficiently? We will see later that there is exists
-another implementation which has only linear complexity.
-
-\paragraph{Example: Merge sort.}
-The insertion sort presented earlier in this chapter is simple to
-formulate, but also not very efficient. It's average complexity is
-proportional to the square of the length of the input list. We now
-design a program to sort the elements of a list which is more
-efficient than insertion sort. A good algorithm for this is {\em merge
-sort}, which works as follows.
-
-First, if the list has zero or one elements, it is already sorted, so
-one returns the list unchanged. Longer lists are split into two
-sub-lists, each containing about half the elements of the original
-list. Each sub-list is sorted by a recursive call to the sort
-function, and the resulting two sorted lists are then combined in a
-merge operation.
-
-For a general implementation of merge sort, we still have to specify
-the type of list elements to be sorted, as well as the function to be
-used for the comparison of elements. We obtain a function of maximal
-generality by passing these two items as parameters. This leads to the
-following implementation.
-\begin{verbatim}
-def msort[a](less: (a, a) => boolean)(xs: List[a]): List[a] = {
- val n = xs.length/2;
- if (n == 0) xs
- else {
- def merge(xs1: List[a], xs2: List[a]): List[a] =
- if (xs1.isEmpty) xs2
- else if (xs2.isEmpty) xs1
- else if (less(xs1.head, xs2.head)) xs1.head :: merge(xs1.tail, xs2)
- else xs2.head :: merge(xs1, xs2.tail);
-
- merge(msort(less)(xs take n), msort(less)(xs drop n))
- }
-}
-\end{verbatim}
-The complexity of \verb@msort@ is $O(N;log(N))$, where $N$ is the
-length of the input list. To see why, note that splitting a list in
-two and merging two sorted lists each take time proportional to the
-length of the argument list(s). Each recursive call of \verb@msort@
-halves the number of elements in its input, so there are $O(log(N))$
-consecutive recursive calls until the base case of lists of length 1
-is reached. However, for longer lists each call spawns off two
-further calls. Adding everything up we obtain that at each of the
-$O(log(N))$ call levels, every element of the original lists takes
-part in one split operation and in one merge operation. Hence, every
-call level has a total cost proportional to $O(N)$. Since there are
-$O(log(N))$ call levels, we obtain an overall cost of
-$O(N;log(N))$. That cost does not depend on the initial distribution
-of elements in the list, so the worst case cost is the same as the
-average case cost. This makes merge sort an attractive algorithm for
-sorting lists.
-
-Here is an example how \verb@msort@ is used.
-\begin{verbatim}
-def iless(x: int, y: int) = x < y
-msort(iless)(List(5, 7, 1, 3))
-\end{verbatim}
-The definition of \verb@msort@ is curried, to make it easy to specialize it with particular
-comparison functions. For instance,
-\begin{verbatim}
-
-val intSort = msort(iless)
-val reverseSort = msort(x: int, y: int => x > y)
-\end{verbatim}
-
-\section*{Higher-Order Methods}
-
-\chapter{Computing with Streams}
-
-The previous chapters have introduced variables, assignment and
-stateful objects. We have seen how real-world objects that change
-with time can be modelled by changing the state of variables in a
-computation. Time changes in the real world thus are modelled by time
-changes in program execution. Of course, such time changes are usually
-stretched out or compressed, but their relative order is the same.
-This seems quite natural, but there is a also price to pay: Our simple
-and powerful substitution model for functional computation is no
-longer applicable once we introduce variables and assignment.
-
-Is there another way? Can we model state change in the real world
-using only immutable functions? Taking mathematics as a guide, the
-answer is clearly yes: A time-changing quantity is simply modelled by
-a function \verb@f(t)@ with a time parameter \verb@t@. The same can be
-done in computation. Instead of overwriting a variable with successive
-values, we represent all these values as successive elements in a
-list. So, a mutabel variable \verb@var x: T@ gets replaced by an
-immutable value \verb@val x: List[T]@. In a sense, we trade space for
-time -- the different values of the variable now all exit concurrently
-as different elements of the list. One advantage of the list-based
-view is that we can ``time-travel'', i.e. view several successive
-values of the variable at the same time. Another advantage is that we
-can make use of the powerful library of list processing functions,
-which often simplifies computation. For instance, consider the way
-imperative way to compute the sum of all prime numbers in an interval:
-\begin{verbatim}
-def sumPrimes(start: int, end: int): int = {
- var i = start;
- var acc = 0;
- while (i < end) {
- if (isPrime(i)) acc = acc + i;
- i = i + 1;
- }
- acc
-}
-\end{verbatim}
-Note that the variable \verb@i@ ``steps through'' all values of the interval
-\verb@[start .. end-1]@.
-%\es\bs
-A more functional way is to represent the list of values of variable \verb@i@ directly as \verb@range(start, end)@. Then the function can be rewritten as follows.
-\begin{verbatim}
-def sumPrimes(start: int, end: int) =
- sum(range(start, end) filter isPrime);
-\end{verbatim}
-
-No contest which program is shorter and clearer! However, the
-functional program is also considerably less efficient since it
-constructs a list of all numbers in the interval, and then another one
-for the prime numbers. Even worse from an efficiency point of view is
-the following example:
-
-To find the second prime number between \verb@1000@ and \verb@10000@:
-\begin{verbatim}
- range(1000, 10000) filter isPrime at 1
-\end{verbatim}
-Here, the list of all numbers between \verb@1000@ and \verb@10000@ is
-constructed. But most of that list is never inspected!
-
-However, we can obtain efficient execution for examples like these by
-a trick:
-\begin{quote}
-%\red
- Avoid computing the tail of a sequence unless that tail is actually
- necessary for the computation.
-\end{quote}
-We define a new class for such sequences, which is called \verb@Stream@.
-
-Streams are created using the constant \verb@empty@ and the constructor \verb@cons@,
-which are both defined in module \verb@scala.Stream@. For instance, the following
-expression constructs a stream with elements \verb@1@ and \verb@2@:
-\begin{verbatim}
-Stream.cons(1, Stream.cons(2, Stream.empty))
-\end{verbatim}
-As another example, here is the analogue of \verb@List.range@,
-but returning a stream instead of a list:
-\begin{verbatim}
-def range(start: Int, end: Int): Stream[Int] =
- if (start >= end) Stream.empty
- else Stream.cons(start, range(start + 1, end));
-\end{verbatim}
-(This function is also defined as given above in module
-\verb@Stream@). Even though \verb@Stream.range@ and \verb@List.range@
-look similar, their execution behavior is completely different:
-
-\verb@Stream.range@ immediately returns with a \verb@Stream@ object
-whose first element is \verb@start@. All other elements are computed
-only when they are \emph{demanded} by calling the \verb@tail@ method
-(which might be never at all).
-
-Streams are accessed just as lists. as for lists, the basic access
-methods are \verb@isEmpty@, \verb@head@ and \verb@tail@. For instance,
-we can print all elements of a stream as follows.
-\begin{verbatim}
-def print(xs: Stream[a]): unit =
- if (!xs.isEmpty) { System.out.println(xs.head); print(xs.tail) }
-\end{verbatim}
-Streams also support almost all other methods defined on lists (see
-below for where their methods sets differ). For instance, we can find
-the second prime number between \verb@1000@ and \verb@10000@ by applying methods
-\verb@filter@ and \verb@at@ on an interval stream:
-\begin{verbatim}
- Stream.range(1000, 10000) filter isPrime at 1
-\end{verbatim}
-The difference to the previous list-based implementation is that now
-we do not needlessly construct and test for primality any numbers
-beyond 3.
-
-\paragraph{Consing and appending streams.} Two methods in class \verb@List@
-which are not supported by class \verb@Stream@ are \verb@::@ and
-\verb@:::@. The reason is that these methods are dispatched on their
-right-hand side argument, which means that this argument needs to be
-evaluated before the method is called. For instance, in the case of
-\verb@x :: xs@ on lists, the tail \verb@xs@ needs to be evaluated
-before \verb@::@ can be called and the new list can be constructed.
-This does not work for streams, where we require that the tail of a
-stream should not be evaluated until it is demanded by a \verb@tail@ operation.
-The argument why list-append \verb@:::@ cannot be adapted to streams is analogous.
-
-Intstead of \verb@x :: xs@, one uses \verb@Stream.cons(x, xs)@ for
-constructing a stream with first element \verb@x@ and (unevaluated)
-rest \verb@xs@. Instead of \verb@xs ::: ys@, one uses the operation
-\verb@xs append ys@.
-
-%\redtext
-{Is there another way?}
-
-
-
-\bibliography{examples}
-\end{document}
-
-
-
-\paragrph{Higher Order Functions
-\bsh{Patterns of Computation over Lists}
-
-\bi
-\item The examples show that functions over lists often have similar
- structures
-\item We can identify several patterns of computation like
- \bi
- \item Transform every element of a list in some way.
- \item Extract from a list all elements satisfying a criterion.
- \item Combine the elements of a list using some operator.
- \ei
-\item Functional programming languages enable programmers to write
- general functions which implement patterns like this
-\item These functions are \redtext{\em higher-order functions} which get
- a transformation or an operator as one argument
-\ei
-\es
-
-Pairs, and tuples or greater arity are useful enough to
-
-
-
-
-
-\chapter{Generic Types and Methods}
-
-Classes in Scala can have type parameters. We demonstrate the use of
-type parameters with iterators as an example. An iterator is an object
-which traverses a sequence of values, using two abstract methods.
-\begin{verbatim}
-abstract class Iterator[a] {
- def hasNext: boolean;
- def next: a;
-\end{verbatim}
-Method \verb@next@ returns successive elements. Method \verb@hasNext@
-indicates whether there are still more elements to be returned by
-\verb@next@. The type of the elements returned by an iterator is
-arbitrary. We express this by giving the class \verb@Iterator@ the
-type parameter \verb@a@. Type parameters are written in square
-brackets, in contrast to normal value parameters, which are written in
-parentheses. Iterators also support other methods, which are
-explained later.
-
-Here's an iterator which traverses an interval of integer values.
-\begin{verbatim}
-class RangeIterator(start: int, end: int) extends Iterator[int] {
- private var current = 0;
- def hasNext = current < end;
- def next = {
- val r = current;
- if (current < end) current = current + 1
- else error("end of iterator");
- r
- }
-}
-\end{verbatim}
-The superclass of \verb@RangeIterator@ is \verb@Iterator[int]@,
-i.e. an iterator returning integer numbers.
-
-Note that, unlike the classes we have seen so far,
-\verb@RangeIterator@ has internal state
-
-
-Here is a function that takes an iterator of arbitrary element type
-\verb@a@ and a procedure that maps \verb@a@-values to the trivial type \verb@unit@.
-It applies the given function to every value returned by the iterator.
-\begin{verbatim}
- def forall[a](i: Iterator[a])(f: a => boolean): boolean =
- !hasNext || { val x = next; f(x) && forall(i, f) }
-\end{verbatim}
-\verb@forEach@ can work with any type of iterator,
-since the iterator's element type is passed as a type parameter \verb@a@.
-Functions that take type parameters are called {\em polymorphic}. The term
-comes from Greek, where it means ``having many forms''.
-
-Finally, here is an application which uses \verb@RangeIterator@ and
-\verb@foreach@ to test whether a given number is prime, i.e. whether it can be
-divided only by 1 and itself.
-\begin{verbatim}
-def isPrime(x: int) =
- forall[int](new RangeIterator(2, n)) { x => x % n != 0 }
-\end{verbatim}
-As always, the actual parameters of \verb@forEach@ correspond to its
-formal parameters. First comes the type parameter \verb@int@, which
-determines the element type of the iterator which is passed next.
-
-\paragraph{Local Type Inference.}
-Passing type parameters such as \verb@[int]@ all the time can become
-tedious in applications where polymorphic functions are used a
-lot. Quite often, the information in a type parameter is redundant,
-because the correct parameter type can also be determined by
-inspecting the function's value parameters or expected result type.
-Taking the \verb@isPrime@ function as an example, we know that its
-first value parameter is of type \verb@Iterator[int]@, so we can
-determine the type parameter \verb@int@ from it. Scala contains a
-fairly powerful local type inferencer which allows one to omit type
-parameters to polymorphic functions and constructors in situations
-like these. In the example above, the \verb@int@ type parameter would
-have been inferred if it was not given explicitly.
-
-Here is another
-application which prints all prime numbers between 1 and 10000.
-\begin{verbatim}
-forall(new RangeIterator(1, 10001)){ x => if (isPrime(x)) System.out.println(x) }
-\end{verbatim}
-This time, the type parameter for \verb@forEach@ was omitted (and was
-inferred to be \verb@int@).
-
-Method \verb@append@ constructs an iterator which resumes with the
-given iterator \verb@it@ after the current iterator has finished.
-\begin{verbatim}
- def append(that: Iterator[a]): Iterator[a] = new Iterator[a] {
- def hasNext = outer.hasNext || that.hasNext;
- def next = if (outer.hasNext) outer.next else that.next;
- }
-\end{verbatim}
-The terms \verb@outer.next@ and \verb@outer.hasNext@ in the definition
-of \verb@append@ call the corresponding methods as they are defined in
-the enclosing \verb@Iterator@ class. Generally, an
-\verb@outer@ prefix in a selection indicates an identifier that is
-visible immediately outside the current class or template. If the
-\verb@outer@ prefix would have been missing,
-\verb@hasNext@ and \verb@next@ would have
-called recursively the methods being defined in the iterator
-constructed by \verb@append@, which is not what we want.
-
-Method \verb@filter@ constructs an iterator which returns all elements
-of the original iterator that satisfy a criterion \verb@p@.
-\begin{verbatim}
- def filter(p: a => boolean) = new Iterator[a] {
- private class Cell[T](elem_: T) { def elem = elem_; }
- private var head: Cell[a] = null;
- private var isAhead = false;
- def hasNext: boolean =
- if (isAhead) true
- else if (outer.hasNext) {
- head = Cell(outer.next); isAhead = p(head.elem); hasNext }
- else false;
- def next: a =
- if (hasNext) { isAhead = false; head.elem }
- else error("next on empty iterator");
- }
-\end{verbatim}
-Method \verb@map@ constructs an iterator which returns all elements of
-the original iterator transformed by a given function \verb@f@.
-\begin{verbatim}
- def map[b](f: a => b) = new Iterator[b] {
- def hasNext: boolean = outer.hasNext;
- def next: b = f(outer.next);
- }
-\end{verbatim}
-The return type of the transformation function \verb@f@ is
-arbitrary. This is expressed by a type parameter \verb@b@ in the
-signature of method \verb@map@, which represents the return type.
-We also say, \verb@map@ is a {\em polymorphic} function.
-
-Method \verb@flatMap@ is like method \verb@map@, except that the
-transformation function \verb@f@ now returns an iterator.
-The result of \verb@flatMap@ is the iterator resulting from appending
-together all iterators returned from successive calls of \verb@f@.
-\begin{verbatim}
- private var cur: Iterator[b] = new EmptyIterator[b];
- def hasNext: boolean =
- if (cur.hasNext) true
- else if (outer.hasNext) { cur = f(outer.next); hasNext }
- else false;
- def next: b =
- if (cur.hasNext) cur.next
- else if (outer.hasNext) { cur = f(outer.next); next }
- else error("next on empty iterator");
- }
-\end{verbatim}
-Finally, method \verb@zip@ takes another iterator and
-returns an iterator consisting of pairs of corresponding elements
-returned by the two iterators.
-\begin{verbatim}
- def zip[b](that: Iterator[b]) = new Iterator[(a, b)] {
- def hasNext = outer.hasNext && that.hasNext;
- def next = (outer.next, that.next);
- }
-} //end iterator;
-\end{verbatim}
-Concrete iterators need to provide implementations for the two
-abstract methods \verb@next@ and \verb@hasNext@ in class
-\verb@Iterator@. The simplest iterator is \verb@EmptyIterator@
-which always returns an empty sequence:
-\begin{verbatim}
-class EmptyIterator[a] extends Iterator[a] {
- def hasNext = false;
- def next: a = error("next on empty iterator");
-}
-\end{verbatim}
-A more interesting iterator enumerates all elements of an array.
-This iterator is formulated here as a polymorphic function. It could
-have also been written as a class, like \verb@EmptyIterator@. The
-difference between the two formulation is that classes also define new
-types, whereas functions do not.
-\begin{verbatim}
-def arrayIterator[a](xs: Array[a]) = new Iterator[a] {
- private var i = 0;
- def hasNext: boolean =
- i < xs.length;
- def next: a =
- if (i < xs.length) { val x = xs(i) ; i = i + 1 ; x }
- else error("next on empty iterator");
-}
-\end{verbatim}
-Another iterator enumerates an integer interval:
-\begin{verbatim}
-def range(lo: int, hi: int) = new Iterator[int] {
- private var i = lo;
- def hasNext: boolean =
- i <= hi;
- def next: int =
- if (i <= hi) { i = i + 1 ; i - 1 }
- else error("next on empty iterator");
-}
-\end{verbatim}
-%In fact, enumerating integer intervals is so common that it is
-%supported by a method
-%\begin{verbatim}
-%def to(hi: int): Iterator[int]
-%\end{verbatim}
-%in class \verb@int@. Hence, one could also write \verb@l to h@ instead of
-%\verb@range(l, h)@.
-All iterators seen so far terminate eventually. It is also possible to
-define iterators that go on forever. For instance, the following
-iterator returns successive integers from some start
-value\footnote{Due to the finite representation of type \prog{int},
-numbers will wrap around at $2^31$.}.
-\begin{verbatim}
-def from(start: int) = new Iterator[int] {
- private var last = start - 1;
- def hasNext = true;
- def next = { last = last + 1; last }
-}
-\end{verbatim}
-Here are two examples how iterators are used. First, to print all
-elements of an array \verb@xs: Array[int]@, one can write:
-\begin{verbatim}
- arrayIterator[int](xs) foreach (x => System.out.println(x))
-\end{verbatim}
-Here, \verb@[int]@ is a type argument clause, which matches the type
-parameter clause \verb@[a]@ of function \verb@arrayIterator@. It
-substitutes the formal argument \verb@int@ for the formal argument
-\verb@a@ in the type of the method that follows. Hence,
-\verb@arrayIterator[a]@ is a function that takes an \verb@Array[int]@
-and that returns an \verb@Iterator[int]@.
-
-In this example, the formal type argument \verb@int@ is redundant
-since it could also have been inferred from the value \verb@xs@, which
-is, after all, an array of \verb@int@. The Scala compiler contains a
-fairly powerful type inferencer which infers type arguments for
-methods and constructors from the types of value arguments and the
-expected return type. In our example, the \verb@[int]@ clause can be
-inferred, so that one can abbreviate to:
-\begin{verbatim}
- arrayIterator(xs) foreach (x => System.out.println(x))
-\end{verbatim}
-%As a second example, consider the problem of finding the indices of
-%all the elements in an array of \verb@double@s greater than some
-%\verb@limit@. The indices should be returned as an iterator.
-%This is achieved by the following expression.
-%\begin{verbatim}
-%arrayIterator(xs)
-% .zip(from(0))
-% .filter(x, i => x > limit)
-% .map(x, i => i)
-%\end{verbatim}
-%The first line in this expression iterates through all array elements,
-%the second lines pairs elements with their indices, the third line
-%selects all value/index pairs where the value is greater than
-%\verb@limit@, and the fourth line returns the index part of all
-%selected pairs.
-
-%Note that we have omitted the type arguments for the calls of
-%\verb@arrayIterator@, \verb@zip@ and \verb@map@. These are all
-%implicitly inserted by the type inferencer.
-
-
-
-\es
-\paragraph{Abstract Methods.}
-Classes can also omit some of the definitions of their members. As an
-example, consider the following class \verb@Ord@ which provides the
-comparison operators \verb@<, >, <=, >=@.
-%\begin{verbatim}
-%abstract class Ord {
-% abstract def <(that: this);
-% def <=(that: this) = this < that || this == that;
-% def >(that: this) = that < this;
-% def >=(that: this) = that <= this;
-%}
-%\end{verbatim}
-\begin{verbatim}
-abstract class Ord {
- def <(that: this): boolean;
- def <=(that: this) = this < that || this == that;
- def >(that: this) = that < this;
- def >=(that: this) = that <= this;
-}
-\end{verbatim}
-Since we want to leave open which objects are compared, we are unable
-to give an implementation for the \verb@<@ method. However, once
-\verb@<@ is given, we can define the other three comparison operators
-in terms of \verb@<@ and the equality test \verb@==@ (which is defined
-in class \verb@Object@). This is expressed by having in \verb@Ord@ an
-{\em abstract} method \verb@<@ to which the implementations of the
-other methods refer.
-
-\paragraph{Self References.} The name \verb@this@ refers in this class
-to the current object. The type of \verb@this@ is also called
-\verb@this@ (generally, every name in Scala can have a definition as a
-term and another one as a type). When used as a type, \verb@this@
-refers to the type of the current object. This type is always
-compatible with the class being defined (\verb@Ord@ in this case).
-
-\paragraph{Mixin Composition.}
-We can now define a class of \verb@Rational@ numbers that
-support comparison operators.
-\begin{verbatim}
-final class OrderedRational(n: int, d: int)
- extends Rational(n, d) with Ord {
- override def ==(that: OrderedRational) =
- numer == that.numer && denom == that.denom;
- def <(that: OrderedRational): boolean =
- numer * that.denom < that.numer * denom;
-}
-\end{verbatim}
-Class \verb@OrderedRational@ redefines method \verb@==@, which is
-defined as reference equality in class \verb@Object@. It also
-implements the abstract method \verb@<@ from class \verb@Ord@. In
-addition, it inherits all members of class \verb@Rational@ and all
-non-abstract members of class \verb@Ord@. The implementations of
-\verb@==@ and \verb@<@ replace the definition of \verb@==@ in class
-\verb@Object@ and the abstract declaration of \verb@<@ in class
-\verb@Ord@. The other inherited comparison methods then refer to this
-implementation in their body.
-
-The clause ``\verb@Rational(d, d) with Ord@'' is an instance of {\em
-mixin composition}. It describes a template for an object that is
-compatible with both \verb@Rational@ and \verb@Ord@ and that contains
-all members of either class. \verb@Rational@ is called the {\em
-superclass} of \verb@OrderedRational@ while \verb@Ord@ is called a
-{\em mixin class}. The type of this template is the {\em compound
-type} ``\verb@Rational with Ord@''.
-
-On the surface, mixin composition looks much like multiple
-inheritance. The difference between the two becomes apparent if we
-look at superclasses of inherited classes. With multiple inheritance,
-both \verb@Rational@ and \verb@Ord@ would contribute a superclass
-\verb@Object@ to the template. We therefore have to answer some
-tricky questions, such as whether members of \verb@Object@ are present
-once or twice and whether the initializer of \verb@Object@ is called
-once or twice. Mixin composition avoids these complications. In the
-mixin composition \verb@Rational with Ord@, class
-\verb@Rational@ is treated as actual superclass of class \verb@Ord@.
-A mixin composition \verb@C with M@ is well-formed as long as the
-first operand \verb@C@ conforms to the declared superclass of the
-second operand \verb@M@. This holds in our example, because
-\verb@Rational@ conforms to \verb@Object@. In a sense, mixin composition
-amounts to overriding the superclass of a class.
-
-\paragraph{Final Classes.}
-Note that class \verb@OrderedRational@ was defined
-\verb@final@. This means that no classes extending \verb@OrderedRational@
-may be defined in other parts of the program.
-%Within final classes the
-%type \verb@this@ is an alias of the defined class itself. Therefore,
-%we could define our \verb@<@ method with an argument of type
-%\verb@OrderedRational@ as a well-formed implementation of the abstract class
-%\verb@less(that: this)@ in class \verb@Ord@.
-
-
-\chapter{Generic Types and Methods}
-
-Classes in Scala can have type parameters. We demonstrate the use of
-type parameters with iterators as an example. An iterator is an object
-which traverses a sequence of values, using two abstract methods.
-\begin{verbatim}
-abstract class Iterator[a] {
- def hasNext: boolean;
- def next: a;
-\end{verbatim}
-Method \verb@next@ returns successive elements. Method \verb@hasNext@
-indicates whether there are still more elements to be returned by
-\verb@next@. The type of elements returned by an iterator is
-arbitrary. We express that by giving the class \verb@Iterator@ the
-type parameter \verb@a@. Type parameters are written in square
-brackets, in contrast to normal value parameters, which are written in
-parentheses. Iterators also support other methods, which are
-explained in the following.
-
-Method \verb@foreach@ applies a procedure (i.e. a function
-returning \verb@unit@ to each element returned by the iterator:
-\begin{verbatim}
- def foreach(f: a => unit): unit =
- while (hasNext) { f(next) }
-\end{verbatim}
-
-Method \verb@append@ constructs an iterator which resumes with the
-given iterator \verb@it@ after the current iterator has finished.
-\begin{verbatim}
- def append(that: Iterator[a]): Iterator[a] = new Iterator[a] {
- def hasNext = outer.hasNext || that.hasNext;
- def next = if (outer.hasNext) outer.next else that.next;
- }
-\end{verbatim}
-The terms \verb@outer.next@ and \verb@outer.hasNext@ in the definition
-of \verb@append@ call the corresponding methods as they are defined in
-the enclosing \verb@Iterator@ class. Generally, an
-\verb@outer@ prefix in a selection indicates an identifier that is
-visible immediately outside the current class or template. If the
-\verb@outer@ prefix would have been missing,
-\verb@hasNext@ and \verb@next@ would have
-called recursively the methods being defined in the iterator
-constructed by \verb@append@, which is not what we want.
-
-Method \verb@filter@ constructs an iterator which returns all elements
-of the original iterator that satisfy a criterion \verb@p@.
-\begin{verbatim}
- def filter(p: a => boolean) = new Iterator[a] {
- private class Cell[T](elem_: T) { def elem = elem_; }
- private var head: Cell[a] = null;
- private var isAhead = false;
- def hasNext: boolean =
- if (isAhead) true
- else if (outer.hasNext) {
- head = Cell(outer.next); isAhead = p(head.elem); hasNext }
- else false;
- def next: a =
- if (hasNext) { isAhead = false; head.elem }
- else error("next on empty iterator");
- }
-\end{verbatim}
-Method \verb@map@ constructs an iterator which returns all elements of
-the original iterator transformed by a given function \verb@f@.
-\begin{verbatim}
- def map[b](f: a => b) = new Iterator[b] {
- def hasNext: boolean = outer.hasNext;
- def next: b = f(outer.next);
- }
-\end{verbatim}
-The return type of the transformation function \verb@f@ is
-arbitrary. This is expressed by a type parameter \verb@b@ in the
-signature of method \verb@map@, which represents the return type.
-We also say, \verb@map@ is a {\em polymorphic} function.
-
-Method \verb@flatMap@ is like method \verb@map@, except that the
-transformation function \verb@f@ now returns an iterator.
-The result of \verb@flatMap@ is the iterator resulting from appending
-together all iterators returned from successive calls of \verb@f@.
-\begin{verbatim}
- private var cur: Iterator[b] = new EmptyIterator[b];
- def hasNext: boolean =
- if (cur.hasNext) true
- else if (outer.hasNext) { cur = f(outer.next); hasNext }
- else false;
- def next: b =
- if (cur.hasNext) cur.next
- else if (outer.hasNext) { cur = f(outer.next); next }
- else error("next on empty iterator");
- }
-\end{verbatim}
-Finally, method \verb@zip@ takes another iterator and
-returns an iterator consisting of pairs of corresponding elements
-returned by the two iterators.
-\begin{verbatim}
- def zip[b](that: Iterator[b]) = new Iterator[(a, b)] {
- def hasNext = outer.hasNext && that.hasNext;
- def next = (outer.next, that.next);
- }
-} //end iterator;
-\end{verbatim}
-Concrete iterators need to provide implementations for the two
-abstract methods \verb@next@ and \verb@hasNext@ in class
-\verb@Iterator@. The simplest iterator is \verb@EmptyIterator@
-which always returns an empty sequence:
-\begin{verbatim}
-class EmptyIterator[a] extends Iterator[a] {
- def hasNext = false;
- def next: a = error("next on empty iterator");
-}
-\end{verbatim}
-A more interesting iterator enumerates all elements of an array.
-This iterator is formulated here as a polymorphic function. It could
-have also been written as a class, like \verb@EmptyIterator@. The
-difference between the two formulation is that classes also define new
-types, whereas functions do not.
-\begin{verbatim}
-def arrayIterator[a](xs: Array[a]) = new Iterator[a] {
- private var i = 0;
- def hasNext: boolean =
- i < xs.length;
- def next: a =
- if (i < xs.length) { val x = xs(i) ; i = i + 1 ; x }
- else error("next on empty iterator");
-}
-\end{verbatim}
-Another iterator enumerates an integer interval:
-\begin{verbatim}
-def range(lo: int, hi: int) = new Iterator[int] {
- private var i = lo;
- def hasNext: boolean =
- i <= hi;
- def next: int =
- if (i <= hi) { i = i + 1 ; i - 1 }
- else error("next on empty iterator");
-}
-\end{verbatim}
-%In fact, enumerating integer intervals is so common that it is
-%supported by a method
-%\begin{verbatim}
-%def to(hi: int): Iterator[int]
-%\end{verbatim}
-%in class \verb@int@. Hence, one could also write \verb@l to h@ instead of
-%\verb@range(l, h)@.
-All iterators seen so far terminate eventually. It is also possible to
-define iterators that go on forever. For instance, the following
-iterator returns successive integers from some start
-value\footnote{Due to the finite representation of type \prog{int},
-numbers will wrap around at $2^31$.}.
-\begin{verbatim}
-def from(start: int) = new Iterator[int] {
- private var last = start - 1;
- def hasNext = true;
- def next = { last = last + 1; last }
-}
-\end{verbatim}
-Here are two examples how iterators are used. First, to print all
-elements of an array \verb@xs: Array[int]@, one can write:
-\begin{verbatim}
- arrayIterator[int](xs) foreach (x => System.out.println(x))
-\end{verbatim}
-Here, \verb@[int]@ is a type argument clause, which matches the type
-parameter clause \verb@[a]@ of function \verb@arrayIterator@. It
-substitutes the formal argument \verb@int@ for the formal argument
-\verb@a@ in the type of the method that follows. Hence,
-\verb@arrayIterator[a]@ is a function that takes an \verb@Array[int]@
-and that returns an \verb@Iterator[int]@.
-
-In this example, the formal type argument \verb@int@ is redundant
-since it could also have been inferred from the value \verb@xs@, which
-is, after all, an array of \verb@int@. The Scala compiler contains a
-fairly powerful type inferencer which infers type arguments for
-methods and constructors from the types of value arguments and the
-expected return type. In our example, the \verb@[int]@ clause can be
-inferred, so that one can abbreviate to:
-\begin{verbatim}
- arrayIterator(xs) foreach (x => System.out.println(x))
-\end{verbatim}
-%As a second example, consider the problem of finding the indices of
-%all the elements in an array of \verb@double@s greater than some
-%\verb@limit@. The indices should be returned as an iterator.
-%This is achieved by the following expression.
-%\begin{verbatim}
-%arrayIterator(xs)
-% .zip(from(0))
-% .filter(x, i => x > limit)
-% .map(x, i => i)
-%\end{verbatim}
-%The first line in this expression iterates through all array elements,
-%the second lines pairs elements with their indices, the third line
-%selects all value/index pairs where the value is greater than
-%\verb@limit@, and the fourth line returns the index part of all
-%selected pairs.
-
-%Note that we have omitted the type arguments for the calls of
-%\verb@arrayIterator@, \verb@zip@ and \verb@map@. These are all
-%implicitly inserted by the type inferencer.
-
-\chapter{\label{sec:for-notation}For-Comprehensions}
-
-The last chapter has demonstrated that the use of higher-order
-functions over sequences can lead to very concise programs. But
-sometimes the level of abstraction required by these functions makes a
-program hard to understand.
-
-Here, Scala's \verb@for@ notation can help. For instance, say we are
-given a sequence \verb@persons@ of persons with \verb@name@ and
-\verb@age@ fields. That sequence could be an array, or a list, or an
-iterator, or some other type implementing the sequence abstraction
-(this will be made more precise below). To print the names of all
-persons in the sequence which are aged over 20, one writes:
-\begin{verbatim}
-for { val p <- persons; p.age > 20 } yield p.name
-\end{verbatim}
-This is equivalent to the following expression , which uses
-higher-order functions \verb@filter@ and \verb@map@:
-\begin{verbatim}
-persons filter (p => p.age > 20) map (p => p.name)
-\end{verbatim}
-The for-expression looks a bit like a for-loop in imperative languages,
-except that it constructs a list of the results of all iterations.
-
-Generally, a for-comprehension is of the form
-\begin{verbatim}
-for ( s ) yield e
-\end{verbatim}
-(Instead of parentheses, braces may also be used.)
-Here, \verb@s@ is a sequence of {\em generators} and {\em filters}.
-\begin{itemize}
-\item A {\em generator} is of the form \verb@val x <- e@,
-where \verb@e@ is a list-valued expression. It binds \verb@x@ to
-successive values in the list.
-\item A {\em filter} is an expression \verb@f@ of type \verb@boolean@.
-It omits from consideration all bindings for which \verb@f@ is \verb@false@.
-\end{itemize}
-The sequence must start with a generator.
-If there are several generators in a sequence, later generators vary
-more rapidly than earlier ones.
-
-Here are two examples that show how for-comprehensions are used.
-
-First, given a positive integer \verb@n@, find all pairs of positive
-integers
-\verb@i@, \verb@j@, where \verb@1 <= j < i <= n@ such that \verb@i + j@ is prime.
-\begin{verbatim}
-for \={ \=val i <- range(1, n);
- \> \>val j <- range(1, i-1);
- \> \>isPrime(i+j)
-} yield (i, j)
-\end{verbatim}
-
-As second example, the scalar product of two vectors \verb@xs@ and
-\verb@ys@ can now be written as
-follows.
-\begin{verbatim}
- sum (for { val (x, y) <- xs zip ys } yield x * y)
-\end{verbatim}
-The for-notation is essentially equivalent to common operations of
-database query languages. For instance, say we are given a book
-database \verb@books@, represented as a list of books, where
-\verb@Book@ is defined as follows.
-\begin{verbatim}
-abstract class Book {
- val title: String;
- val authors: List[String]
-}
-\end{verbatim}
-\begin{verbatim}
-val books: List[Book] = [
- new Book {
- val title = "Structure and Interpretation of Computer Programs";
- val authors = ["Abelson, Harald", "Sussman, Gerald J."];
- },
- new Book {
- val title = "Principles of Compiler Design";
- val authors = ["Aho, Alfred", "Ullman, Jeffrey"];
- },
- new Book {
- val title = "Programming in Modula-2";
- val authors = ["Wirth, Niklaus"];
- }
-];
-\end{verbatim}
-Then, to find the titles of all books whose author's last name is ``Ullman'':
-\begin{verbatim}
-for { val b <- books; val a <- b.authors; a startsWith "Ullman"
-} yield b.title
-\end{verbatim}
-(Here, \verb@startsWith@ is a method in \verb@java.lang.String@). Or,
-to find the titles of all books that have the string ``Program'' in
-their title:
-\begin{verbatim}
-for { val b <- books; (b.title indexOf "Program") >= 0
-} yield b.title
-\end{verbatim}
-Or, to find the names of all authors that have written at least two
-books in the database.
-\begin{verbatim}
-for { \=val b1 <- books;
- \>val b2 <- books;
- \>b1 != b2;
- \>val a1 <- b1.authors;
- \>val a2 <- b2.authors;
- \>a1 == a2 } yield a1
-\end{verbatim}
-The last solution is not yet perfect, because authors will appear
-several times in the list of results. We still need to remove
-duplicate authors from result lists. This can be achieved with the
-following function.
-\begin{verbatim}
-def removeDuplicates[a](xs: List[a]): List[a] =
- if (xs.isEmpty) xs
- else xs.head :: removeDuplicates(xs.tail filter (x => x != xs.head));
-\end{verbatim}
-The last expression can be equivalently expressed as follows.
-\begin{verbatim}
-xs.head :: removeDuplicates(for (val x <- xs.tail; x != xs.head) yield x)
-\end{verbatim}
-
-\subsection*{Translation of \prog{for}}
-
-Every for-comprehensions can be expressed in terms of the three
-higher-order functions \verb@map@, \verb@flatMap@ and \verb@filter@.
-Here is the translation scheme, which is also used by the Scala compiler.
-\begin{itemize}
-\item
-A simple for-comprehension
-\begin{verbatim}
-for (val x <- e) yield e'
-\end{verbatim}
-is translated to
-\begin{verbatim}
-e.map(x => e')
-\end{verbatim}
-\item
-A for-comprehension
-\begin{verbatim}
-for (val x <- e; f; s) yield e'
-\end{verbatim}
-where \verb@f@ is a filter and \verb@s@ is a (possibly empty)
-sequence of generators or filters
-is translated to
-\begin{verbatim}
-for (val x <- e.filter(x => f); s) yield e'
-\end{verbatim}
-and then translation continues with the latter expression.
-\item
-A for-comprehension
-\begin{verbatim}
-for (val x <- e; y <- e'; s) yield e''
-\end{verbatim}
-where \verb@s@ is a (possibly empty)
-sequence of generators or filters
-is translated to
-\begin{verbatim}
-e.flatMap(x => for (y <- e'; s) yield e'')
-\end{verbatim}
-and then translation continues with the latter expression.
-\end{itemize}
-For instance, taking our "pairs of integers whose sum is prime" example:
-\begin{verbatim}
-for \= { \= val i <- range(1, n);
- \> \> val j <- range(1, i-1);
- \> \> isPrime(i+j)
-} yield (i, j)
-\end{verbatim}
-Here is what we get when we translate this expression:
-\begin{verbatim}
-range(1, n)
- .flatMap(i =>
- range(1, i-1)
- .filter(j => isPrime(i+j))
- .map(j => (i, j)))
-\end{verbatim}
-
-\exercise
-Define the following function in terms of \verb@for@.
-\begin{verbatim}
-def concat(xss: List[List[a]]): List[a] =
- (xss foldr []) { xs, ys => xs ::: ys }
-\end{verbatim}
-\exercise
-Translate
-\begin{verbatim}
-for { val b <- books; val a <- b.authors; a startsWith "Bird" } yield b.title
-for { val b <- books; (b.title indexOf "Program") >= 0 } yield b.title
-\end{verbatim}
-to higher-order functions.
-
-We have seen that the for-translation only relies on the presence of
-methods \verb@map@,
-\verb@flatMap@, and \verb@filter@.
-This gives programmers the possibility to have for-syntax for
-other types as well -- one only needs to define \verb@map@,
-\verb@flatMap@, and \verb@filter@ for these types.
-That's also why we were able to define \verb@for@ at the same time for
-arrays, iterators, and lists -- all these types have the required
-three methods \verb@map@,\verb@flatMap@, and \verb@filter@ as members.
-Of course, it is also possible for users and library designers to
-define other types with these methods. There are many examples where
-this is useful: Databases, XML trees, optional values. We will see in
-Chapter~\ref{sec:parsers-results} how for-comprehensions can be used in the
-definition of parsers for context-free grammars that construct
-abstract syntax trees.
-
-\chapter{\label{sec:simple-examples}Pattern Matching}
-
-\todo{Complete}
-
-Consider binary trees whose leafs contain integer arguments. This can
-be described by a class for trees, with subclasses for leafs and
-branch nodes:
-\begin{verbatim}
-abstract class Tree;
-case class Branch(left: Tree, right: Tree) extends Tree;
-case class Leaf(x: int) extends Tree;
-\end{verbatim}
-Note that the class \verb@Tree@ is not followed by an extends
-clause or a body. This defines \verb@Tree@ to be an empty
-subclass of \verb@Object@, as if we had written
-\begin{verbatim}
-class Tree extends Object {}
-\end{verbatim}
-Note also that the two subclasses of \verb@Tree@ have a \verb@case@
-modifier. That modifier has two effects. First, it lets us construct
-values of a case class by simply calling the constructor, without
-needing a preceding \verb@new@. Example:
-\begin{verbatim}
-val tree1 = Branch(Branch(Leaf(1), Leaf(2)), Branch(Leaf(3), Leaf(4)))
-\end{verbatim}
-Second, it lets us use constructors for these classes in patterns, as
-is illustrated in the following example.
-\begin{verbatim}
-def sumLeaves(t: Tree): int = t match {
- case Branch(l, r) => sumLeaves(l) + sumLeaves(r)
- case Leaf(x) => x
-}
-\end{verbatim}
-The function \verb@sumLeaves@ sums up all the integer values in the
-leaves of a given tree \verb@t@. It is is implemented by calling the
-\verb@match@ method of \verb@t@ with a {\em choice expression} as
-argument (\verb@match@ is a predefined method in class \verb@Object@).
-The choice expression consists of two cases which both
-relate a pattern with an expression. The pattern of the first case,
-\verb@Branch(l, r)@ matches all instances of class \verb@Branch@
-and binds the {\em pattern variables} \verb@l@ and \verb@r@ to the
-constructor arguments, i.e.\ the left and right subtrees of the
-branch. Pattern variables always start with a lower case letter; to
-avoid ambiguities, constructors in patterns should start with an upper
-case letter.
-
-The effect of the choice expression is to select the first alternative
-whose pattern matches the given select value, and to evaluate the body
-of this alternative in a context where pattern variables are bound to
-corresponding parts of the selector. For instance, the application
-\verb@sumLeaves(tree1)@ would select the first alternative with the
-\verb@Branch(l,r)@ pattern, and would evaluate the expression
-\verb@sumLeaves(l) + sumLeaves(r)@ with bindings
-\begin{verbatim}
-l = Branch(Leaf(1), Leaf(2)), r = Branch(Leaf(3), Leaf(4)).
-\end{verbatim}
-As another example, consider the following class
-\begin{verbatim}
-abstract final class Option[+a];
-case object None extends Option[All];
-case class Some[a](item: a) extends Option[a];
-\end{verbatim}
-...
-
-%\todo{Several simple and intermediate examples needed}.
-
-\begin{verbatim}
-def find[a,b](it: Iterator[(a, b)], x: a): Option[b] = {
- var result: Option[b] = None;
- while (it.hasNext && result == None) {
- val (x1, y) = it.next;
- if (x == x1) result = Some(y)
- }
- result
-}
-find(xs, x) match {
- case Some(y) => System.out.println(y)
- case None => System.out.println("no match")
-}
-\end{verbatim}
-
-\comment{
-
-
-class MaxCounter {
- var maxVal: Option[int] = None;
- def set(x: int) = maxVal match {
- case None => maxVal = Some(x)
- case Some(y) => maxVal = Some(Math.max(x, y))
- }
-}
-\end{verbatim}
-}
-\comment{
-\begin{verbatim}
-class Stream[a] = List[a]
-
-module Stream {
- def concat(xss: Stream[Stream[a]]): Stream[a] = {
- let result: Stream[a] = xss match {
- case [] => []
- case [] :: xss1 => concat(xss1)
- case (x :: xs) :: xss1 => x :: concat(xs :: xss1)
- }
- result
- }
-}
-\end{verbatim}
-}
-\comment{
-\chapter{Implementing Abstract Types: Search Trees}
-
-This chapter presents unbalanced binary search trees, implemented in
-three different styles: algebraic, object-oriented, and imperative.
-In each case, a search tree package is seen as an implementation
-of a class {\em MapStruct}.
-\begin{verbatim}
-abstract class MapStruct[kt, vt] {
- abstract type Map extends kt => vt {
- def apply(key: kt): vt;
- def extend(key: kt, value: vt): Map;
- def remove(key: kt): Map;
- def domain: Stream[kt];
- def range: Stream[vt];
- }
- def empty: Map;
-}
-\end{verbatim}
-The \verb@MapStruct@ class is parameterized with a type of keys
-\verb@kt@ and a type of values \verb@vt@. It
-specifies an abstract type \verb@Map@ and an abstract value
-\verb@empty@, which represents empty maps. Every implementation
-\verb@Map@ needs to conform to that abstract type, which
-extends the function type \verb@kt => vt@
-with four new
-methods. The method \verb@domain@ yields a stream that enumerates the
-map's domain, i.e. the set of keys that are mapped to non-null values.
-The method \verb@range@ yields a stream that enumerates the function's
-range, i.e.\ the values obtained by applying the function to arguments
-in its domain. The method
-\verb@extend@ extends the map with a given key/value binding, whereas
-\verb@remove@ removes a given key from the map's domain. Both
-methods yield a new map value as result, which has the same
-representation as the receiver object.
-
-\begin{figure}[t]
-\begin{verbatim}
-class AlgBinTree[kt extends Ord, vt] extends MapStruct[kt, vt] {
- private case
- Empty extends Map,
- Node(key: kt, value: vt, l: Map, r: Map) extends Map
-
- final class Map extends kt => vt {
- def apply(key: kt): vt = this match {
- case Empty => null
- case Node(k, v, l, r) =>
- if (key < k) l.apply(key)
- else if (key > k) r.apply(key)
- else v
- }
-
- def extend(key: kt, value: vt): Map = this match {
- case Empty => Node(k, v, Empty, Empty)
- case Node(k, v, l, r) =>
- if (key < k) Node(k, v, l.extend(key, value), r)
- else if (key > k) Node(k, v, l, r.extend(key, value))
- else Node(k, value, l, r)
- }
-
- def remove(key: kt): Map = this match {
- case Empty => Empty
- case Node(k, v, l, r) =>
- if (key < k) Node(k, v, l.remove(key), r)
- else if (key > k) Node(k, v, l, r.remove(key))
- else if (l == Empty) r
- else if (r == Empty) l
- else {
- val midKey = r.domain.head
- Node(midKey, r.apply(midKey), l, r.remove(midKey))
- }
- }
-
- def domain: Stream[kt] = this match {
- case Empty => []
- case Node(k, v, l, r) => Stream.concat([l.domain, [k], r.domain])
- }
- def range: Stream[vt] = this match {
- case Empty => []
- case Node(k, v, l, r) => Stream.concat([l.range, [v], r.range])
- }
- }
- def empty: Map = Empty
-}
-\end{verbatim}
-\caption{\label{fig:algbintree}Algebraic implementation of binary
-search trees}
-\end{figure}
-We now present three implementations of \verb@Map@, which are all
-based on binary search trees. The \verb@apply@ method of a map is
-implemented in each case by the usual search function over binary
-trees, which compares a given key with the key stored in the topmost
-tree node, and depending on the result of the comparison, searches the
-left or the right hand sub-tree. The type of keys must implement the
-\verb@Ord@ class, which contains comparison methods
-(see Chapter~\ref{chap:classes} for a definition of class \verb@Ord@).
-
-The first implementation, \verb@AlgBinTree@, is given in
-Figure~\ref{fig:algbintree}. It represents a map with a
-data type \verb@Map@ with two cases, \verb@Empty@ and \verb@Node@.
-
-Every method of \verb@AlgBinTree[kt, vt].Map@ performs a pattern
-match on the value of
-\verb@this@ using the \verb@match@ method which is defined as postfix
-function application in class \verb@Object@ (\sref{sec:class-object}).
-
-The functions \verb@domain@ and \verb@range@ return their results as
-lazily constructed lists. The \verb@Stream@ class is an alias of
-\verb@List@ which should be used to indicate the fact that its values
-are constructed lazily.
-
-\begin{figure}[thb]
-\begin{verbatim}
-class OOBinTree[kt extends Ord, vt] extends MapStruct[kt, vt] {
- abstract class Map extends kt => vt {
- def apply(key: kt): v
- def extend(key: kt, value: vt): Map
- def remove(key: kt): Map
- def domain: Stream[kt]
- def range: Stream[vt]
- }
- module empty extends Map {
- def apply(key: kt) = null
- def extend(key: kt, value: vt) = Node(key, value, empty, empty)
- def remove(key: kt) = empty
- def domain = []
- def range = []
- }
- private class Node(k: kt, v: vt, l: Map, r: Map) extends Map {
- def apply(key: kt): vt =
- if (key < k) l.apply(key)
- else if (key > k) r.apply(key)
- else v
- def extend(key: kt, value: vt): Map =
- if (key < k) Node(k, v, l.extend(key, value), r)
- else if (key > k) Node(k, v, l, r.extend(key, value))
- else Node(k, value, l, r)
- def remove(key: kt): Map =
- if (key < k) Node(k, v, l.remove(key), r)
- else if (key > k) Node(k, v, l, r.remove(key))
- else if (l == empty) r
- else if (r == empty) l
- else {
- val midKey = r.domain.head
- Node(midKey, r(midKey), l, r.remove(midKey))
- }
- def domain: Stream[kt] = Stream.concat([l.domain, [k], r.domain] )
- def range: Stream[vt] = Stream.concat([l.range, [v], r.range])
- }
-}
-\end{verbatim}
-\caption{\label{fig:oobintree}Object-oriented implementation of binary
-search trees}
-\end{figure}
-
-The second implementation of maps is given in
-Figure~\ref{fig:oobintree}. Class \verb@OOBinTree@ implements the
-type \verb@Map@ with a module \verb@empty@ and a class
-\verb@Node@, which define the behavior of empty and non-empty trees,
-respectively.
-
-Note the different nesting structure of \verb@AlgBinTree@ and
-\verb@OOBinTree@. In the former, all methods form part of the base
-class \verb@Map@. The different behavior of empty and non-empty trees
-is expressed using a pattern match on the tree itself. In the
-latter, each subclass of \verb@Map@ defines its own set of
-methods, which override the methods in the base class. The pattern
-matches of the algebraic implementation have been replaced by the
-dynamic binding that comes with method overriding.
-
-Which of the two schemes is preferable depends to a large degree on
-which extensions of the type are anticipated. If the type is later
-extended with a new alternative, it is best to keep methods in each
-alternative, the way it was done in \verb@OOBinTree@. On the other
-hand, if the type is extended with additional methods, then it is
-preferable to keep only one implementation of methods and to rely on
-pattern matching, since this way existing subclasses need not be
-modified.
-
-\begin{figure}
-\begin{verbatim}
-class MutBinTree[kt extends Ord, vt] extends MapStruct[kt, vt] {
- class Map(key: kt, value: vt) extends kt => vt {
- val k = key
- var v = value
- var l = empty, r = empty
-
- def apply(key: kt): vt =
- if (this eq empty) null
- else if (key < k) l.apply(key)
- else if (key > k) r.apply(key)
- else v
-
- def extend(key: kt, value: vt): Map =
- if (this eq empty) Map(key, value)
- else {
- if (key < k) l = l.extend(key, value)
- else if (key > k) r = r.extend(key, value)
- else v = value
- this
- }
-
- def remove(key: kt): Map =
- if (this eq empty) this
- else if (key < k) { l = l.remove(key) ; this }
- else if (key > k) { r = r.remove(key) ; this }
- else if (l eq empty) r
- else if (r eq empty) l
- else {
- var mid = r
- while (!(mid.l eq empty)) { mid = mid.l }
- mid.r = r.remove(mid.k)
- mid.l = l
- mid
- }
-
- def domain: Stream[kt] = Stream.concat([l.domain, [k], r.domain])
- def range: Stream[vt] = Stream.concat([l.range, [v], r.range])
- }
- let empty = new Map(null, null)
-}
-\end{verbatim}
-\caption{\label{fig:impbintree}Side-effecting implementation of binary
-search trees}
-\end{figure}
-
-The two versions of binary trees presented so far are {\em
-persistent}, in the sense that maps are values that cannot be changed
-by side effects. By contrast, in the next implementation of binary
-trees, the implementations of \verb@extend@ and
-\verb@remove@ do have an effect on the state of their receiver
-object. This corresponds to the way binary trees are usually
-implemented in imperative languages. The new implementation can lead
-to some savings in computing time and memory allocation, but care is
-required not to use the original tree after it has been modified by a
-side-effecting operation.
-
-In this implementation, \verb@value@, \verb@l@ and \verb@r@ are
-variables that can be affected by method calls. The
-class \verb@MutBinTree[kt, vt].Map@ takes two instance parameters
-which define the \verb@key@ value and the initial value of the
-\verb@value@ variable. Empty trees are represented by a
-value \verb@empty@, which has \verb@null@ (signifying undefined) in
-both its key and value fields. Note that this value needs to be
-defined lazily using \verb@let@ since its definition involves the
-creation of a
-\verb@Map@ object,
-which accesses \verb@empty@ recursively as part of its initialization.
-All methods test first whether the current tree is empty using the
-reference equality operator \verb@eq@ (\sref{sec:class-object}).
-
-As a program using the \verb@MapStruct@ abstraction, consider a function
-which creates a map from strings to integers and then applies it to a
-key string:
-\begin{verbatim}
-def mapTest(def mapImpl: MapStruct[String, int]): int = {
- val map: mapImpl.Map = mapImpl.empty.extend("ab", 1).extend("bx", 3)
- val x = map("ab") // returns 1
-}
-\end{verbatim}
-The function is parameterized with the particular implementation of
-\verb@MapStruct@. It can be applied to any one of the three implementations
-described above. E.g.:
-\begin{verbatim}
-mapTest(AlgBinTree[String, int])
-mapTest(OOBinTree[String, int])
-mapTest(MutBinTree[String, int])
-\end{verbatim}
-}
-\chapter{Programming with Higher-Order Functions: Combinator Parsing}
-
-In this chapter we describe how to write combinator parsers in
-Scala. Such parsers are constructed from predefined higher-order
-functions, so called parser combinators, that closely model the
-constructions of an EBNF grammar \cite{ebnf}.
-
-As running example, we consider parsers for arithmetic expressions
-described by the following context-free grammar.
-\bda{p{3cm}cp{10cm}}
-letter &::=& /* all letters */ \\
-digit &::=& /* all digits */ \\[0.5em]
-ident &::=& letter \{letter $|$ digit \}\\
-number &::=& digit \{digit\}\\[0.5em]
-
-expr &::=& expr1 \{`+' expr1 $|$ `$-$' expr1\}\\
-expr1 &::=& expr2 \{`*' expr2 $|$ `/' expr2\}\\
-expr2 &::=& ident $|$ number $|$ `(' expr `)'
-\eda
-
-\section{Simple Combinator Parsing}
-
-In this section we will only be concerned with the task of recognizing
-input strings, not with processing them. So we can describe parsers
-by the sets of input strings they accept. There are two
-fundamental operators over parsers:
-\verb@&&&@ expresses the sequential composition of a parser with
-another, while \verb@|||@ expresses an alternative. These operations
-will both be defined as methods of a \verb@Parser@ class. We will
-also define constructors for the following primitive parsers:
-
-\begin{quote}\begin{tabular}{ll}
-\verb@empty@ & The parser that accepts the empty string
-\\
-\verb@fail@ & The parser that accepts no string
-\\
-\verb@chr@ & The parser that accepts any character.
-\\
-\verb@chr(c: char)@
- & The parser that accepts the single-character string ``$c$''.
-\\
-\verb@chrWith(p: char => boolean)@
- & The parser that accepts single-character strings
- ``$c$'' \\
- & for which $p(c)$ is true.
-\end{tabular}\end{quote}
-
-There are also the two higher-order parser combinators \verb@opt@,
-expressing optionality and \verb@rep@, expressing repetition.
-For any parser $p$, \verb@opt($p$)@ yields a parser that
-accepts the strings accepted by $p$ or else the empty string, while
-\verb@rep($p$)@ accepts arbitrary sequences of the strings accepted by
-$p$. In EBNF, \verb@opt($p$)@ corresponds to $[p]$ and \verb@rep($p$)@
-corresponds to $\{p\}$.
-
-The central idea of parser combinators is that parsers can be produced
-by a straightforward rewrite of the grammar, replacing \verb@::=@ with
-\verb@=@, sequencing with
-\verb@&&&@, choice
-\verb@|@ with \verb@|||@, repetition \verb@{...}@ with
-\verb@rep(...)@ and optional occurrence with \verb@[...]@.
-Applying this process to the grammar of arithmetic
-expressions yields:
-\begin{verbatim}
-module ExprParser {
- import Parse;
-
- def letter \= = \= chrWith(c => c.isLetter);
- def digit \= = \> chrWith(c => c.isDigit);
-
- def ident \> = \> letter &&& rep(letter ||| digit);
- def number \> = \> digit &&& rep(digit);
-
- def expr:Parser\> = expr1 &&& rep((chr('+') &&& expr1) ||| (chr('-') &&& expr1));
- def expr1 \> = expr2 &&& rep((chr('*') &&& expr2) ||| (chr('/') &&& expr2));
- def expr2 \> = ident ||| number ||| (chr('(') &&& expr &&& chr(')'));
-}
-\end{verbatim}
-It remains to explain how to implement a library with the combinators
-described above. We will pack combinators and their underlying
-implementation in a module \verb@Parse@. The first question to decide
-is which underlying representation type to use for a parser. We treat
-parsers here as functions that take a list of characters as input
-parameter and that yield a parse result.
-\begin{verbatim}
-module Parse {
-
- type Result = Option[List[char]];
-
- abstract class Parser extends Function1[List[char],Result] {
-\end{verbatim}
-\comment{
-The \verb@Option@ type is predefined as follows.
-\begin{verbatim}
-abstract final class Option[a];
-case class None[a] extends Option[a];
-case class Some[a](x: a) extends Option[a];
-\end{verbatim}
-}
-A parser returns either the constant \verb@None@, which
-signifies that the parser did not recognize a legal input string, or
-it returns a value \verb@Some(in1)@ where \verb@in1@ represents that
-part of the input list that the parser did not consume.
-
-Parsers are instances of functions from \verb@List[char]@ to
-\verb@Parse.Result@, which also implement the combinators
-for sequence and alternative. This is modeled by
-defining \verb@Parser@ as a class that extends type
-\verb@Function1[List[char],Result]@ and that defines an \verb@apply@
-method, as well as methods \verb@&&&@ and \verb@|||@.
-\begin{verbatim}
- abstract def apply(in: List[char]): Result;
-\end{verbatim}
-\begin{verbatim}
- def &&& (def p: Parser) = new Parser {
- def apply(in: List[char]) = outer.apply(in) match {
- case Some(in1) => p(in1)
- case n => n
- }
- }
-
- def ||| (def p: Parser) = new Parser {
- def apply(in: List[char]) = outer.apply(in) match {
- case None => p(in)
- case s => s
- }
- }
- }
-\end{verbatim}
-The implementations of the primitive parsers \verb@empty@, \verb@fail@,
-\verb@chrWith@ and \verb@chr@ are as follows.
-\begin{verbatim}
-
- def empty = new Parser { def apply(in: List[char]) = Some(in) }
-
- def fail = new Parser { def apply(in: List[char]) = None[List[char]] }
-
- def chrWith(p: char => boolean) = new Parser {
- def apply(in: List[char]) = in match {
- case [] => None[List[char]]
- case (c :: in1) => if (p(c)) Some(in1) else None[List[char]]
- }
- }
-
- def chr(c: char): Parser = chrWith(d => d == c);
-\end{verbatim}
-The higher-order parser combinators \verb@opt@ and \verb@rep@ can be
-defined in terms of the combinators for sequence and alternative:
-\begin{verbatim}
- def opt(p: Parser): Parser = p ||| empty;
- def rep(p: Parser): Parser = opt(rep1(p));
- def rep1(p: Parser): Parser = p &&& rep(p);
-} // end Parser
-\end{verbatim}
-This is all that's needed. Parsers such as the one for arithmetic
-expressions given above can now be composed from these building
-blocks. These parsers need not refer to the underlying implementation of
-parsers as functions from input lists to parse results.
-
-The presented combinator parsers use backtracking to change from one
-alternative to another. If one restricts the focus to LL(1) grammars,
-a non-backtracking implementation of parsers is also possible. This
-implementation can then be based on iterators instead of lists.
-
-\section{\label{sec:parsers-results}Parsers that Return Results}
-
-The combinator library of the previous section does not support the
-generation of output from parsing. But usually one does not just want
-to check whether a given string belongs to the defined language, one
-also wants to convert the input string into some internal
-representation such as an abstract syntax tree.
-
-In this section, we modify our parser library to build parsers that
-produce results. We will make use of the for-comprehensions introduced
-in Chapter~\ref{sec:for-notation}. The basic combinator of sequential
-composition, formerly \verb@p &&& q@, now becomes
-\begin{verbatim}
-for (val x <- p; val y <- q) yield e
-\end{verbatim}.
-Here, the names \verb@x@ and \verb@y@ are bound to the results of
-executing the parsers \verb@p@ and \verb@q@. \verb@e@ is an expression
-that uses these results to build the tree returned by the composed
-parser.
-
-Before describing the implementation of the new parser combinators, we
-explain how the new building blocks are used. Say we want to modify
-our arithmetic expression parser so that it returns an abstract syntax
-tree of the parsed expression. The class of syntax trees is given by:
-\begin{verbatim}
-abstract class Tree;
-case class Var(n: String) extends Tree;
-case class Num(n: int) extends Tree;
-case class Binop(op: char, l: Tree, r: Tree) extends Tree;
-\end{verbatim}
-That is, a syntax tree is a named variable, an integer number, or a
-binary operation with two operand trees and a character indicating the
-operation.
-
-As a first step towards parsers that produce syntax trees, we need to
-modify the ``micro-syntax'' parsers \verb@letter@, \verb@digit@,
-\verb@ident@ and \verb@number@ so that they return representations of
-the parsed input:
-\begin{verbatim}
-def letter: Parser[char] = chrWith(c => c.isLetter);
-def digit : Parser[char] = chrWith(c => c.isDigit);
-
-def ident: Parser[String] =
- for (val c <- letter; val cs <- rep(letter ||| digit))
- yield ((c :: cs) foldr "") {c, s => c+ s};
-
-def number: Parser[int] =
- for (val d <- digit; val ds <- rep(digit))
- yield ((d - '0') :_foldl ds) {x, y => x * 10 + (y - '0')};
-\end{verbatim}
-The \verb@letter@ and \verb@digit@ parsers simply return the letter
-that was parsed. The \verb@ident@ and \verb@number@ parsers return the
-string, respectively integer number that was parsed. In both cases,
-sub-parsers are applied in a for-comprehension and their results are
-embedded in the result of the calling parser. The remainder of the
-parser for arithmetic expressions follows the same scheme.
-\begin{verbatim}
-def expr: Parser[Tree] =
- for {
- val e1 <- expr1;
- val es <- rep (
- for {
- val op <- chr('+') ||| chr('-');
- val e <- expr1
- } yield (x => Binop(op, x, e)) : Tree => Tree
- )
- } yield applyAll(es, e1);
-\end{verbatim}
-\begin{verbatim}
-def expr1: Parser[Tree] =
- for {
- val e1 <- expr2;
- val es <- rep (
- for {
- val op <- chr('*') ||| chr('/');
- val e <- expr2
- } yield (x => Binop(op, x, e)) : Tree => Tree
- )
- } yield applyAll(es, e1);
-\end{verbatim}
-\begin{verbatim}
-def expr2: Parser[Tree] = {
- \= ( for { val n <- ident } yield Var(n) : Tree )
- |||\> ( for { val n <- number } yield Num(n) : Tree )
- |||\> ( for { val _ <- chr('('); val e <- expr; val _ <- chr(')') } yield e );
-}
-\end{verbatim}
-Note the treatment of the repetitions in \verb@expr@ and
-\verb@expr1@. The parser for an expression suffix $op;e$ consisting of an
-operator $op$ and an expression $e$ returns a function, which, given a
-left operand expression $d$, constructs a \verb@Binop@ node that
-represents $d;op;e$. The \verb@rep@ parser combinator forms a list of
-all these functions. The final \verb@yield@ part applies all functions
-to the first operand in the sequence, which is represented by
-\verb@e1@. Here \verb@applyAll@ applies the list of functions passed as its first
-argument to its second argument. It is defined as follows.
-\begin{verbatim}
-def applyAll[a](fs: List[a => a], e: a): a =
- (e :_foldl fs) { x, f => f(x) }
-\end{verbatim}
-We now present the parser combinators that support the new
-scheme. Parsers that succeed now return a parse result besides the
-un-consumed input.
-\begin{verbatim}
-module Parse {
-
- type Result[a] = Option[(a, List[char])]
-\end{verbatim}
-Parsers are parameterized with the type of their result. The class
-\verb@Parser[a]@ now defines new methods \verb@map@, \verb@flatMap@
-and \verb@filter@. The \verb@for@ expressions are mapped by the
-compiler to calls of these functions using the scheme described in
-Chapter~\ref{sec:for-notation}.
-
-Here is the complete definition of the new \verb@Parser@ class.
-\begin{verbatim}
- abstract class Parser[a] extends Function1[List[char],Result[a]] {
-
- def apply(in: List[char]): Result[a];
-
- def filter(p: a => boolean) = new Parser[a] {
- def apply(in: List[char]): Result[a] = outer.apply(in) match {
- case Some((x, in1)) => if (p(x)) Some((x, in1)) else None
- case None => None
- }
- }
-
- def map[b](f: a => b) = new Parser[b] {
- def apply(in: List[char]): Result[b] = outer.apply(in) match {
- case Some((x, in1)) => Some((f(x), in1))
- case None => None
- }
- }
-
- def flatMap[b](f: a => Parser[b]) = new Parser[b] {
- def apply(in: List[char]): Result[b] = outer.apply(in) match {
- case Some((x, in1)) => f(x)(in1)
- case None => None
- }
- }
-
- def ||| (def p: Parser[a]) = new Parser[a] {
- def apply(in: List[char]): Result[a] = outer.apply(in) match {
- case None => p(in)
- case s => s
- }
- }
-
- def &&& [b](def p: Parser[b]): Parser[b] =
- for (val _ <- this; val result <- p) yield result;
- }
-\end{verbatim}
-
-The \verb@filter@ method takes as parameter a predicate $p$ which it
-applies to the results of the current parser. If the predicate is
-false, the parser fails by returning \verb@None@; otherwise it returns
-the result of the current parser. The \verb@map@ method takes as
-parameter a function $f$ which it applies to the results of the
-current parser. The \verb@flatMap@ tales as parameter a function
-\verb@f@ which returns a parser. It applies \verb@f@ to the result of
-the current parser and then continues with the resulting parser. The
-\verb@|||@ method is essentially defined as before. The
-\verb@&&&@ method can now be defined in terms of \verb@for@.
-
-% Here is the code for fail, chrWith and chr
-%
-%\begin{verbatim}
-% def fail[a] = new Parser[a] { def apply(in: List[char]) = None[(a,List[char])] }
-%
-% def chrWith(p: char => boolean) = new Parser[char] {
-% def apply(in: List[char]) = in match {
-% case [] => None[(char,List[char])]
-% case (c :: in1) => if (p(c)) Some((c,in1)) else None[(char,List[char])]
-% }
-% }
-%
-% def chr(c: char): Parser[char] = chrWith(d => d == c);
-%\end{verbatim}
-The primitive parser \verb@succeed@ replaces \verb@empty@. It consumes
-no input and returns its parameter as result.
-\begin{verbatim}
- def succeed[a](x: a) = new Parser[a] {
- def apply(in: List[char]) = Some((x, in))
- }
-\end{verbatim}
-The \verb@fail@ parser is as before. The parser combinators
-\verb@rep@ and \verb@opt@ now also return results. \verb@rep@ returns
-a list which contains as elements the results of each iteration of its
-sub-parser. \verb@opt@ returns an
-\verb@Option@ type which indicates whether something was recognized by
-its sub-parser.
-\begin{verbatim}
- def rep[a](p: Parser[a]): Parser[List[a]] =
- rep1(p) ||| succeed([]);
-
- def rep1[a](p: Parser[a]): Parser[List[a]] =
- for (val x <- p; val xs <- rep(p)) yield x :: xs;
-
- def opt[a](p: Parser[a]): Parser[Option [a]] =
- { for (val x <- p) yield (Some(x): Option[a]) } ||| succeed((None: Option[a]));
-} // end Parse
-\end{verbatim}
-
-\chapter{\label{sec:hm}Programming with Patterns: Hindley/Milner Type Inference}
-
-This chapter demonstrates Scala's data types and pattern matching by
-developing a type inference system in the Hindley/Milner style. The
-source language for the type inferencer is lambda calculus with a let
-construct. Abstract syntax trees for the source language are
-represented by the following data type of \verb@Terms@.
-\begin{verbatim}
-abstract class Term;
-case class Var(x: String) extends Term;
-case class Lam(x: String, e: Term) extends Term;
-case class App(f: Term, e: Term) extends Term;
-case class Let(x: String, e: Term, f: Term) extends Term;
-\end{verbatim}
-There are four tree constructors: \verb@Var@ for variables, \verb@Lam@
-for function abstractions, \verb@App@ for function applications, and
-\verb@Let@ for let expressions. Note that these tree constructors are
-defined outside the \verb@Term@ class. It would also be possible
-to define further constructors for this type in other parts of the
-program.
-
-The next data type describes the form of types that are
-computed by the inference system.
-\begin{verbatim}
-module Types {
- abstract final class Type;
- case class Tyvar(a: String) extends Type;
- case class Arrow(t1: Type, t2: Type) extends Type;
- case class Tycon(k: String, ts: List[Type]) extends Type;
- private var n: int = 0;
- def newTyvar: Type = { n = n + 1 ; Tyvar("a" + n) }
-}
-import Types;
-\end{verbatim}
-There are three type constructors: \verb@Tyvar@ for type variables,
-\verb@Arrow@ for function types and \verb@Tycon@ for type
-constructors such as \verb@boolean@ or \verb@List@. Type constructors
-have as component a list of their type parameters. This list is empty
-for type constants such as \verb@boolean@. The data type is packaged
-in a module \verb@Types@. Also contained in that module is a function
-\verb@newTyvar@ which creates a fresh type variable each time it is
-called. The module definition is followed by an import clause
-\verb@import Types@, which makes the non-private members of
-this module available without qualification in the code that follows.
-
-Note that \verb@Type@ is a \verb@final@ class. This means that no
-subclasses or data constructors that extend \verb@Type@ can be formed
-except for the three constructors that follow the class. This makes
-\verb@Type@ into a {\em closed} algebraic data type with a fixed
-number of alternatives. By contrast, type \verb@Term@ is an {\em open}
-algebraic type for which further alternatives can be defined.
-
-The next data type describes type schemes, which consist of a type and
-a list of names of type variables which appear universally quantified
-in the type scheme. For instance, the type scheme $\forall a\forall
-b.a \arrow b$ would be represented in the type checker as:
-\begin{verbatim}
-TypeScheme(["a", "b"], Arrow(Tyvar("a"), Tyvar("b"))) .
-\end{verbatim}
-The data type definition of type schemes does not carry an extends
-clause; this means that type schemes extend directly class
-\verb@Object@.
-Even though there is only one possible way to construct a type scheme,
-a \verb@case class@ representation was chosen since it offers a convenient
-way to decompose a type scheme into its parts using pattern matching.
-\begin{verbatim}
-case class TypeScheme(ls: List[String], t: Type) {
- def newInstance: Type = {
- val instSubst =
- ((EmptySubst: Subst) :_foldl ls) { s, a => s.extend(Tyvar(a), newTyvar) }
- instSubst(t)
- }
-}
-\end{verbatim}
-Type scheme objects come with a method \verb@newInstance@, which
-returns the type contained in the scheme after all universally type
-variables have been renamed to fresh variables.
-
-The next class describes substitutions. A substitution is an
-idempotent function from type variables to types. It maps a finite
-number of given type variables to given types, and leaves all other
-type variables unchanged. The meaning of a substitution is extended
-point-wise to a mapping from types to types.
-
-\begin{verbatim}
-abstract class Subst extends Function1[Type,Type] {
- def lookup(x: Tyvar): Type;
- def apply(t: Type): Type = t match {
- case Tyvar(a) => val u = lookup(Tyvar(a)); if (t == u) t else apply(u);
- case Arrow(t1, t2) => Arrow(apply(t1), apply(t2))
- case Tycon(k, ts) => Tycon(k, ts map apply)
- }
- def extend(x: Tyvar, t: Type) = new Subst {
- def lookup(y: Tyvar): Type = if (x == y) t else outer.lookup(y);
- }
-}
-case class EmptySubst extends Subst { def lookup(t: Tyvar): Type = t }
-\end{verbatim}
-We represent substitutions as functions, of type
-\verb@Type => Type@. To be an instance of this type, a
-substitution \verb@s@ has to implement an \verb@apply@ method that takes a
-\verb@Type@ as argument and yields another \verb@Type@ as result. A function
-application \verb@s(t)@ is then interpreted as \verb@s.apply(t)@.
-
-The \verb@lookup@ method is abstract in class \verb@Subst@. Concrete
-substitutions are defined by the case class \verb@EmptySubst@ and the
-method \verb@extend@ in class \verb@Subst@.
-
-The next class gives a naive implementation of sets using lists as the
-implementation type. It implements methods \verb@contains@ for
-membership tests as well as \verb@union@ and \verb@diff@ for set union
-and difference. Alternatively, one could have used a more efficient
-implementation of sets in some standard library.
-\begin{verbatim}
-class ListSet[a](xs: List[a]) {
- val elems: List[a] = xs;
-
- def contains(y: a): boolean = xs match {
- case [] => false
- case x :: xs1 => (x == y) || (xs1 contains y)
- }
-
- def union(ys: ListSet[a]): ListSet[a] = xs match {
- case [] => ys
- case x :: xs1 =>
- if (ys contains x) ListSet(xs1) union ys
- else ListSet(x :: (ListSet(xs1) union ys).elems)
- }
-
- def diff(ys: ListSet[a]): ListSet[a] = xs match {
- case [] => ListSet([])
- case x :: xs1 =>
- if (ys contains x) ListSet(xs1) diff ys
- else ListSet(x :: (ListSet(xs1) diff ys).elems)
- }
-}
-\end{verbatim}
-
-We now present the type checker module. The type checker
-computes a type for a given term in a given environment. Environments
-associate variable names with type schemes. They are represented by a
-type alias \verb@Env@ in module \verb@TypeChecker@:
-\begin{verbatim}
-module TypeChecker {
-
- /** Type environments are lists of bindings that associate a
- * name with a type scheme.
- */
- type Env = List[(String, TypeScheme)];
-\end{verbatim}
-There is also an exception \verb@TypeError@, which is thrown when type
-checking fails. Exceptions are modeled as case classes that inherit
-from the predefined \verb@Exception@ class.
-\begin{verbatim}
- case class TypeError(msg: String) extends Exception(msg);
-\end{verbatim}
-The \verb@Exception@ class defines a \verb@throw@ method which causes
-the exception to be thrown.
-
-The \verb@TypeChecker@ module contains several utility
-functions. Function
-\verb@tyvars@ yields the set of free type variables of a type,
-of a type scheme, of a list of types, or of an environment. Its
-implementation is as four overloaded functions, one for each type of
-argument.
-\begin{verbatim}
- def tyvars(t: Type): ListSet[String] = t match {
- case Tyvar(a) => new ListSet([a])
- case Arrow(t1, t2) => tyvars(t1) union tyvars(t2)
- case Tycon(k, ts) => tyvars(ts)
- }
- def tyvars(ts: TypeScheme): ListSet[String] = ts match {
- case TypeScheme(as, t) => tyvars(t) diff new ListSet(as)
- }
- def tyvars(ts: List[Type]): ListSet[String] = ts match {
- case [] => new ListSet[String]([])
- case t :: ts1 => tyvars(t) union tyvars(ts1)
- }
- def tyvars(env: Env): ListSet[String] = env match {
- case [] => new ListSet[String]([])
- case (x, t) :: env1 => tyvars(t) union tyvars(env1)
- }
-\end{verbatim}
-The next utility function, \verb@lookup@, returns the type scheme
-associated with a given variable name in the given environment, or
-returns \verb@null@ if no binding for the variable exists in the environment.
-\begin{verbatim}
- def lookup(env: Env, x: String): TypeScheme = env match {
- case [] => null
- case (y, t) :: env1 => if (x == y) t else lookup(env1, x)
- }
-\end{verbatim}
-The next utility function, \verb@gen@, returns the type scheme that
-results from generalizing a given type in a given environment. This
-means that all type variables that occur in the type but not in the
-environment are universally quantified.
-\begin{verbatim}
- def gen(env: Env, t: Type): TypeScheme =
- TypeScheme((tyvars(t) diff tyvars(env)).elems, t);
-\end{verbatim}
-The next utility function, \verb@mgu@, computes the most general
-unifier of two given types $t$ and $u$ under a pre-existing
-substitution $s$. That is, it returns the most general
-substitution $s'$ which extends $s$, and which makes $s'(t)$ and
-$s'(u)$ equal types. The function throws a \verb@TypeError@ exception
-if no such substitution exists. This can happen because the two types
-have different type constructors at corresponding places, or because
-a type variable is unified with a type that contains the type variable
-itself.
-\begin{verbatim}
- def mgu(t: Type, u: Type)(s: Subst): Subst = (s(t), s(u)) match {
- case (Tyvar( a), Tyvar(b)) if a == b =>
- s
- case (Tyvar(a), _) =>
- if (tyvars(u) contains a)
- TypeError("unification failure: occurs check").throw
- else s.extend(Tyvar(a), u)
- case (_, Tyvar(a)) =>
- mgu(u, t)(s)
- case (Arrow(t1, t2), Arrow(u1, u2)) =>
- mgu(t1, u1)(mgu(t2, u2)(s))
- case (Tycon(k1, ts), Tycon(k2, us)) if k1 == k2 =>
- (s :_foldl ((ts zip us) map (case (t,u) => mgu(t,u)))) { s, f => f(s) }
- case _ => TypeError("unification failure").throw
- }
-\end{verbatim}
-The main task of the type checker is implemented by function
-\verb@tp@. This function takes as first parameters an environment $env$, a
-term $e$ and a proto-type $t$. As a second parameter it takes a
-pre-existing substitution $s$. The function yields a substitution
-$s'$ that extends $s$ and that
-turns $s'(env) \ts e: s'(t)$ into a derivable type judgment according
-to the derivation rules of the Hindley/Milner type system \cite{hindley-milner}. A
-\verb@TypeError@ exception is thrown if no such substitution exists.
-\begin{verbatim}
- def tp(env: Env, e: Term, t: Type)(s: Subst): Subst = e match {
- case Var(x) => {
- val u = lookup(env, x);
- if (u == null) TypeError("undefined: x").throw
- else mgu(u.newInstance, t)(s)
- }
- case Lam(x, e1) => {
- val a = newTyvar, b = newTyvar;
- val s1 = mgu(t, Arrow(a, b))(s);
- val env1 = (x, TypeScheme([], a)) :: env;
- tp(env1, e1, b)(s1)
- }
- case App(e1, e2) => {
- val a = newTyvar;
- val s1 = tp(env, e1, Arrow(a, t))(s);
- tp(env, e2, a)(s1)
- }
- case Let(x, e1, e2) => {
- val a = newTyvar;
- val s1 = tp(env, e1, a)(s);
- tp((x, gen(env, s1(a))) :: env, e2, t)(s1)
- }
- }
-\end{verbatim}
-The next function, \verb@typeOf@ is a simplified facade for
-\verb@tp@. It computes the type of a given term $e$ in a given
-environment $env$. It does so by creating a fresh type variable \verb$a$,
-computing a typing substitution that makes \verb@env $\ts$ e: a@ into
-a derivable type judgment, and finally by returning the result of
-applying the substitution to $a$.
-\begin{verbatim}
- def typeOf(env: Env, e: Term): Type = {
- val a = newTyvar;
- tp(env, e, a)(EmptySubst)(a)
- }
-}
-\end{verbatim}
-This concludes the presentation of the type inference system.
-To apply the system, it is convenient to have a predefined environment
-that contains bindings for commonly used constants. The module
-\verb@Predefined@ defines an environment \verb@env@ that contains
-bindings for booleans, numbers and lists together with some primitive
-operations over these types. It also defines a fixed point operator
-\verb@fix@, which can be used to represent recursion.
-\begin{verbatim}
-module Predefined {
- val booleanType = Tycon("Boolean", []);
- val intType = Tycon("Int", []);
- def listType(t: Type) = Tycon("List", [t]);
-
- private def gen(t: Type): TypeScheme = TypeChecker.gen([], t);
- private val a = newTyvar;
- val env = [
- ("true", gen(booleanType)),
- ("false", gen(booleanType)),
- ("$\mbox{\prog{if}}$", gen(Arrow(booleanType, Arrow(a, Arrow(a, a))))),
- ("zero", gen(intType)),
- ("succ", gen(Arrow(intType, intType))),
- ("$\mbox{\prog{nil}}$", gen(listType(a))),
- ("cons", gen(Arrow(a, Arrow(listType(a), listType(a))))),
- ("isEmpty", gen(Arrow(listType(a), booleanType))),
- ("head", gen(Arrow(listType(a), a))),
- ("tail", gen(Arrow(listType(a), listType(a)))),
- ("fix", gen(Arrow(Arrow(a, a), a)))
- ];
-}
-\end{verbatim}
-Here's an example how the type inferencer is used.
-Let's define a function \verb@showType@ which returns the type of
-a given term computed in the predefined environment
-\verb@Predefined.env@:
-\begin{verbatim}
-> def showType(e: Term) = TypeChecker.typeOf(Predefined.env, e);
-\end{verbatim}
-Then the application
-\begin{verbatim}
-> showType(Lam("x", App(App(Var("cons"), Var("x")), Var("$\mbox{\prog{nil}}$"))));
-\end{verbatim}
-would give the response
-\begin{verbatim}
-> TypeScheme([a0], Arrow(Tyvar(a0), Tycon("List", [Tyvar(a0)])));
-\end{verbatim}
-
-\exercise
-Add \verb@toString@ methods to the data constructors of class
-\verb@Type@ and \verb@TypeScheme@ which represent types in a more
-natural way.
-
-\chapter{Abstractions for Concurrency}\label{sec:ex-concurrency}
-
-This section reviews common concurrent programming patterns and shows
-how they can be implemented in Scala.
-
-\section{Signals and Monitors}
-
-\example
-The {\em monitor} provides the basic means for mutual exclusion
-of processes in Scala. It is defined as follows.
-\begin{verbatim}
-class Monitor {
- def synchronized [a] (def e: a): a;
-}
-\end{verbatim}
-The \verb@synchronized@ method in class \verb@Monitor@ executes its
-argument computation \verb@e@ in mutual exclusive mode -- at any one
-time, only one thread can execute a \verb@synchronized@ argument of a
-given monitor.
-
-Threads can suspend inside a monitor by waiting on a signal. The
-\verb@Signal@ class offers two methods \verb@send@ and
-\verb@wait@. Threads that call the \verb@wait@ method wait until a
-\verb@send@ method of the same signal is called subsequently by some
-other thread. Calls to \verb@send@ with no threads waiting for the
-signal are ignored. Here is the specification of the \verb@Signal@
-class.
-\begin{verbatim}
-class Signal {
- def wait: unit;
- def wait(msec: long): unit;
- def notify: unit;
- def notifyAll: unit;
-}
-\end{verbatim}
-A signal also implements a timed form of \verb@wait@, which blocks
-only as long as no signal was received or the specified amount of time
-(given in milliseconds) has elapsed. Furthermore, there is a
-\verb@notifyAll@ method which unblocks all threads which wait for the
-signal. \verb@Signal@ and \verb@Monitor@ are primitive classes in
-Scala which are implemented in terms of the underlying runtime system.
-
-As an example of how monitors and signals are used, here is is an
-implementation of a bounded buffer class.
-\begin{verbatim}
-class BoundedBuffer[a](N: int) extends Monitor {
- var in = 0, out = 0, n = 0;
- val elems = new Array[a](N);
- val nonEmpty = new Signal;
- val nonFull = new Signal;
-\end{verbatim}
-\begin{verbatim}
- def put(x: a) = synchronized {
- if (n == N) nonFull.wait;
- elems(in) = x ; in = (in + 1) % N ; n = n + 1;
- if (n == 1) nonEmpty.send;
- }
-\end{verbatim}
-\begin{verbatim}
- def get: a = synchronized {
- if (n == 0) nonEmpty.wait
- val x = elems(out) ; out = (out + 1) % N ; n = n - 1;
- if (n == N - 1) nonFull.send;
- x
- }
-}
-\end{verbatim}
-And here is a program using a bounded buffer to communicate between a
-producer and a consumer process.
-\begin{verbatim}
-val buf = new BoundedBuffer[String](10)
-fork { while (true) { val s = produceString ; buf.put(s) } }
-fork { while (true) { val s = buf.get ; consumeString(s) } }
-\end{verbatim}
-The \verb@fork@ method spawns a new thread which executes the
-expression given in the parameter. It can be defined as follows.
-\begin{verbatim}
-def fork(def e: unit) = {
- val p = new Thread { def run = e; }
- p.run
-}
-\end{verbatim}
-
-\comment{
-\section{Logic Variable}
-
-A logic variable (or lvar for short) offers operations \verb@:=@
-and \verb@value@ to define the variable and to retrieve its value.
-Variables can be \verb@define@d only once. A call to \verb@value@
-blocks until the variable has been defined.
-
-Logic variables can be implemented as follows.
-
-\begin{verbatim}
-class LVar[a] extends Monitor {
- private val defined = new Signal
- private var isDefined: boolean = false
- private var v: a
- def value = synchronized {
- if (!isDefined) defined.wait
- v
- }
- def :=(x: a) = synchronized {
- v = x ; isDefined = true ; defined.send
- }
-}
-\end{verbatim}
-}
-
-\section{SyncVars}
-
-A synchronized variable (or syncvar for short) offers \verb@get@ and
-\verb@put@ operations to read and set the variable. \verb@get@ operations
-block until the variable has been defined. An \verb@unset@ operation
-resets the variable to undefined state.
-
-Synchronized variables can be implemented as follows.
-\begin{verbatim}
-class SyncVar[a] extends Monitor {
- private val defined = new Signal;
- private var isDefined: boolean = false;
- private var value: a;
- def get = synchronized {
- if (!isDefined) defined.wait;
- value
- }
- def set(x: a) = synchronized {
- value = x ; isDefined = true ; defined.send;
- }
- def isSet: boolean =
- isDefined;
- def unset = synchronized {
- isDefined = false;
- }
-}
-\end{verbatim}
-
-\section{Futures}
-\label{sec:futures}
-
-A {\em future} is a value which is computed in parallel to some other
-client thread, to be used by the client thread at some future time.
-Futures are used in order to make good use of parallel processing
-resources. A typical usage is:
-
-\begin{verbatim}
-val x = future(someLengthyComputation);
-anotherLengthyComputation;
-val y = f(x()) + g(x());
-\end{verbatim}
-
-Futures can be implemented in Scala as follows.
-
-\begin{verbatim}
-def future[a](def p: a): unit => a = {
- val result = new SyncVar[a];
- fork { result.set(p) }
- (=> result.get)
-}
-\end{verbatim}
-
-The \verb@future@ method gets as parameter a computation \verb@p@ to
-be performed. The type of the computation is arbitrary; it is
-represented by \verb@future@'s type parameter \verb@a@. The
-\verb@future@ method defines a guard \verb@result@, which takes a
-parameter representing the result of the computation. It then forks
-off a new thread that computes the result and invokes the
-\verb@result@ guard when it is finished. In parallel to this thread,
-the function returns an anonymous function of type \verb@a@.
-When called, this functions waits on the result guard to be
-invoked, and, once this happens returns the result argument.
-At the same time, the function reinvokes the \verb@result@ guard with
-the same argument, so that future invocations of the function can
-return the result immediately.
-
-\section{Parallel Computations}
-
-The next example presents a function \verb@par@ which takes a pair of
-computations as parameters and which returns the results of the computations
-in another pair. The two computations are performed in parallel.
-
-\begin{verbatim}
-def par[a, b](def xp: a, def yp: b): (a, b) = {
- val y = new SyncVar[a];
- fork { y.set(yp) }
- (xp, y)
-}
-\end{verbatim}
-
-The next example presents a function \verb@replicate@ which performs a
-number of replicates of a computation in parallel. Each
-replication instance is passed an integer number which identifies it.
-
-\begin{verbatim}
-def replicate(start: int, end: int)(def p: int => unit): unit = {
- if (start == end) {
- } else if (start + 1 == end) {
- p(start)
- } else {
- val mid = (start + end) / 2;
- par ( replicate(start, mid)(p), replicate(mid, end)(p) )
- }
-}
-\end{verbatim}
-
-The next example shows how to use \verb@replicate@ to perform parallel
-computations on all elements of an array.
-
-\begin{verbatim}
-def parMap[a,b](f: a => b, xs: Array[a]): Array[b] = {
- val results = new Array[b](xs.length);
- replicate(0, xs.length) { i => results(i) = f(xs(i)) }
- results
-}
-\end{verbatim}
-
-\section{Semaphores}
-
-A common mechanism for process synchronization is a {\em lock} (or:
-{\em semaphore}). A lock offers two atomic actions: \prog{acquire} and
-\prog{release}. Here's the implementation of a lock in Scala:
-
-\begin{verbatim}
-class Lock extends Monitor with Signal {
- var available = true;
- def acquire = {
- if (!available) wait;
- available = false
- }
- def release = {
- available = true;
- notify
- }
-}
-\end{verbatim}
-
-\section{Readers/Writers}
-
-A more complex form of synchronization distinguishes between {\em
-readers} which access a common resource without modifying it and {\em
-writers} which can both access and modify it. To synchronize readers
-and writers we need to implement operations \prog{startRead}, \prog{startWrite},
-\prog{endRead}, \prog{endWrite}, such that:
-\begin{itemize}
-\item there can be multiple concurrent readers,
-\item there can only be one writer at one time,
-\item pending write requests have priority over pending read requests,
-but don't preempt ongoing read operations.
-\end{itemize}
-The following implementation of a readers/writers lock is based on the
-{\em message space} concept (see Section~\ref{sec:messagespace}).
-
-\begin{verbatim}
-class ReadersWriters {
- val m = new MessageSpace;
- private case class Writers(n: int), Readers(n: int);
- Writers(0); Readers(0);
- def startRead = m receive {
- case Writers(n) if n == 0 => m receive {
- case Readers(n) => Writers(0) ; Readers(n+1);
- }
- }
- def startWrite = m receive {
- case Writers(n) =>
- Writers(n+1);
- m receive { case Readers(n) if n == 0 => }
- }
-\end{verbatim}
-\begin{verbatim}
- def endRead = receive {
- case Readers(n) => Readers(n-1)
- }
- def endWrite = receive {
- case Writers(n) => Writers(n-1) ; if (n == 0) Readers(0)
- }
-}
-\end{verbatim}
-
-\section{Asynchronous Channels}
-
-A fundamental way of interprocess communication is the asynchronous
-channel. Its implementation makes use the following class for linked
-lists:
-\begin{verbatim}
-class LinkedList[a](x: a) {
- val elem: a = x;
- var next: LinkedList[a] = null;
-}
-\end{verbatim}
-To facilitate insertion and deletion of elements into linked lists,
-every reference into a linked list points to the node which precedes
-the node which conceptually forms the top of the list.
-Empty linked lists start with a dummy node, whose successor is \verb@null@.
-
-The channel class uses a linked list to store data that has been sent
-but not read yet. In the opposite direction, a signal \verb@moreData@ is
-used to wake up reader threads that wait for data.
-\begin{verbatim}
-class Channel[a] {
- private val written = new LinkedList[a](null);
- private var lastWritten = written;
- private val moreData = new Signal;
-
- def write(x: a) = {
- lastWritten.next = new LinkedList(x);
- lastWritten = lastWritten.next;
- moreData.notify;
- }
-
- def read: a = {
- if (written.next == null) moreData.wait;
- written = written.next;
- written.elem;
- }
-}
-\end{verbatim}
-
-\section{Synchronous Channels}
-
-Here's an implementation of synchronous channels, where the sender of
-a message blocks until that message has been received. Synchronous
-channels only need a single variable to store messages in transit, but
-three signals are used to coordinate reader and writer processes.
-\begin{verbatim}
-class SyncChannel[a] {
- val data = new SyncVar[a];
-
- def write(x: a): unit = synchronized {
- val empty = new Signal, full = new Signal, idle = new Signal;
- if (data.isSet) idle.wait;
- data.put(x);
- full.send;
- empty.wait;
- data.unset;
- idle.send;
- }
-
- def read: a = synchronized {
- if (!(data.isSet)) full.wait;
- x = data.get;
- empty.send;
- x
- }
-}
-\end{verbatim}
-
-\section{Workers}
-
-Here's an implementation of a {\em compute server} in Scala. The
-server implements a \verb@future@ method which evaluates a given
-expression in parallel with its caller. Unlike the implementation in
-Section~\ref{sec:futures} the server computes futures only with a
-predefined number of threads. A possible implementation of the server
-could run each thread on a separate processor, and could hence avoid
-the overhead inherent in context-switching several threads on a single
-processor.
-
-\begin{verbatim}
-class ComputeServer(n: int) {
- private abstract class Job {
- abstract type t;
- def task: t;
- def return(x: t): unit;
- }
-
- private val openJobs = new Channel[Job]
-
- private def processor: unit = {
- while (true) {
- val job = openJobs.read;
- job.return(job.task)
- }
- }
-\end{verbatim}
-\begin{verbatim}
- def future[a](def p: a): () => a = {
- val reply = new SyncVar[a];
- openJobs.write(
- new Job {
- type t = a;
- def task = p;
- def return(x: a) = reply.set(x);
- }
- )
- (=> reply.get)
- }
-
- replicate(n){processor};
-}
-\end{verbatim}
-
-Expressions to be computed (i.e. arguments
-to calls of \verb@future@) are written to the \verb@openJobs@
-channel. A {\em job} is an object with
-\begin{itemize}
-\item
-An abstract type \verb@t@ which describes the result of the compute
-job.
-\item
-A parameterless \verb@task@ method of type \verb@t@ which denotes
-the expression to be computed.
-\item
-A \verb@return@ method which consumes the result once it is
-computed.
-\end{itemize}
-The compute server creates $n$ \verb@processor@ processes as part of
-its initialization. Every such process repeatedly consumes an open
-job, evaluates the job's \verb@task@ method and passes the result on
-to the job's
-\verb@return@ method. The polymorphic \verb@future@ method creates
-a new job where the \verb@return@ method is implemented by a guard
-named \verb@reply@ and inserts this job into the set of open jobs by
-calling the \verb@isOpen@ guard. It then waits until the corresponding
-\verb@reply@ guard is called.
-
-The example demonstrates the use of abstract types. The abstract type
-\verb@t@ keeps track of the result type of a job, which can vary
-between different jobs. Without abstract types it would be impossible
-to implement the same class to the user in a statically type-safe
-way, without relying on dynamic type tests and type casts.
-
-\section{Message Spaces}
-\label{sec:messagespace}
-
-Message spaces are high-level, flexible constructs for process
-synchronization and communication. A {\em message} in this context is
-an arbitrary object. There is a special message \verb@TIMEOUT@ which
-is used to signal a time-out.
-\begin{verbatim}
-case class TIMEOUT;
-\end{verbatim}
-Message spaces implement the following signature.
-\begin{verbatim}
-class MessageSpace {
- def send(msg: Any): unit;
- def receive[a](f: PartialFunction[Any, a]): a;
- def receiveWithin[a](msec: long)(f: PartialFunction[Any, a]): a;
-}
-\end{verbatim}
-The state of a message space consists of a multi-set of messages.
-Messages are added to the space using the \verb@send@ method. Messages
-are removed using the \verb@receive@ method, which is passed a message
-processor \verb@f@ as argument, which is a partial function from
-messages to some arbitrary result type. Typically, this function is
-implemented as a pattern matching expression. The \verb@receive@
-method blocks until there is a message in the space for which its
-message processor is defined. The matching message is then removed
-from the space and the blocked thread is restarted by applying the
-message processor to the message. Both sent messages and receivers are
-ordered in time. A receiver $r$ is applied to a matching message $m$
-only if there is no other (message, receiver) pair which precedes $(m,
-r)$ in the partial ordering on pairs that orders each component in
-time.
-
-As a simple example of how message spaces are used, consider a
-one-place buffer:
-\begin{verbatim}
-class OnePlaceBuffer {
- private val m = new MessageSpace; \=// An internal message space
- private case class Empty, Full(x: int); \>// Types of messages we deal with
-
- m send Empty; \>// Initialization
-
- def write(x: int): unit =
- m receive { case Empty => m send Full(x) }
-
- def read: int =
- m receive { case Full(x) => m send Empty ; x }
-}
-\end{verbatim}
-Here's how the message space class can be implemented:
-\begin{verbatim}
-class MessageSpace {
-
- private abstract class Receiver extends Signal {
- def isDefined(msg: Any): boolean;
- var msg = null;
- }
-\end{verbatim}
-We define an internal class for receivers with a test method
-\verb@isDefined@, which indicates whether the receiver is
-defined for a given message. The receiver inherits from class
-\verb@Signal@ a \verb@notify@ method which is used to wake up a
-receiver thread. When the receiver thread is woken up, the message it
-needs to be applied to is stored in the \verb@msg@ variable of
-\verb@Receiver@.
-\begin{verbatim}
- private val sent = new LinkedList[Any](null) ;
- private var lastSent = sent;
- private var receivers = new LinkedList[Receiver](null);
- private var lastReceiver = receivers;
-\end{verbatim}
-The message space class maintains two linked lists,
-one for sent but unconsumed messages, the other for waiting receivers.
-\begin{verbatim}
- def send(msg: Any): unit = synchronized {
- var r = receivers, r1 = r.next;
- while (r1 != null && !r1.elem.isDefined(msg)) {
- r = r1; r1 = r1.next;
- }
- if (r1 != null) {
- r.next = r1.next; r1.elem.msg = msg; r1.elem.notify;
- } else {
- l = new LinkedList(msg); lastSent.next = l; lastSent = l;
- }
- }
-\end{verbatim}
-The \verb@send@ method first checks whether a waiting receiver is
-
-applicable to the sent message. If yes, the receiver is notified.
-Otherwise, the message is appended to the linked list of sent messages.
-\begin{verbatim}
- def receive[a](f: PartialFunction[Any, a]): a = {
- val msg: Any = synchronized {
- var s = sent, s1 = s.next;
- while (s1 != null && !f.isDefined(s1.elem)) {
- s = s1; s1 = s1.next
- }
- if (s1 != null) {
- s.next = s1.next; s1.elem
- } else {
- val r = new LinkedList(
- new Receiver {
- def isDefined(msg: Any) = f.isDefined(msg);
- });
- lastReceiver.next = r; lastReceiver = r;
- r.elem.wait;
- r.elem.msg
- }
- }
- f(msg)
- }
-\end{verbatim}
-The \verb@receive@ method first checks whether the message processor function
-\verb@f@ can be applied to a message that has already been sent but that
-was not yet consumed. If yes, the thread continues immediately by
-applying \verb@f@ to the message. Otherwise, a new receiver is created
-and linked into the \verb@receivers@ list, and the thread waits for a
-notification on this receiver. Once the thread is woken up again, it
-continues by applying \verb@f@ to the message that was stored in the receiver.
-
-The message space class also offers a method \verb@receiveWithin@
-which blocks for only a specified maximal amount of time. If no
-message is received within the specified time interval (given in
-milliseconds), the message processor argument $f$ will be unblocked
-with the special \verb@TIMEOUT@ message. The implementation of
-\verb@receiveWithin@ is quite similar to \verb@receive@:
-\begin{verbatim}
- def receiveWithin[a](msec: long)(f: PartialFunction[Any, a]): a = {
- val msg: Any = synchronized {
- var s = sent, s1 = s.next;
- while (s1 != null && !f.isDefined(s1.elem)) {
- s = s1; s1 = s1.next ;
- }
- if (s1 != null) {
- s.next = s1.next; s1.elem
- } else {
- val r = new LinkedList(
- new Receiver {
- def isDefined(msg: Any) = f.isDefined(msg);
- }
- )
- lastReceiver.next = r; lastReceiver = r;
- r.elem.wait(msec);
- if (r.elem.msg == null) r.elem.msg = TIMEOUT;
- r.elem.msg
- }
- }
- f(msg)
- }
-} // end MessageSpace
-\end{verbatim}
-The only differences are the timed call to \verb@wait@, and the
-statement following it.
-
-\section{Actors}
-\label{sec:actors}
-
-Chapter~\ref{sec:ex-auction} sketched as a program example the
-implementation of an electronic auction service. This service was
-based on high-level actor processes, that work by inspecting messages
-in their mailbox using pattern matching. An actor is simply a thread
-whose communication primitives are those of a message space.
-Actors are therefore defined by a mixin composition of threads and message spaces.
-\begin{verbatim}
-abstract class Actor extends Thread with MessageSpace;
-\end{verbatim}
-
-\comment{
-As an extended example of an application that uses actors, we come
-back to the auction server example of Section~\ref{sec:ex-auction}.
-The following code implements:
-
-\begin{figure}[thb]
-\begin{verbatim}
-class AuctionMessage;
-case class
- \=Offer(bid: int, client: Process), \=// make a bid
- \>Inquire(client: Process) extends AuctionMessage \>// inquire status
-
-class AuctionReply;
-case class
- \=Status(asked; int, expiration: Date), \>// asked sum, expiration date
- \>BestOffer, \>// yours is the best offer
- \>BeatenOffer(maxBid: int), \>// offer beaten by maxBid
- \>AuctionConcluded(seller: Process, client: Process), \>// auction concluded
- \>AuctionFailed \>// failed with no bids
- \>AuctionOver extends AuctionReply \>// bidding is closed
-\end{verbatim}
-\end{figure}
-
-\begin{verbatim}
-class Auction(seller: Process, minBid: int, closing: Date)
- extends Process {
-
- val timeToShutdown = 36000000 // msec
- val delta = 10 // bid increment
-\end{verbatim}
-\begin{verbatim}
- def run = {
- var askedBid = minBid
- var maxBidder: Process = null
- while (true) {
- receiveWithin ((closing - Date.currentDate).msec) {
- case Offer(bid, client) => {
- if (bid >= askedBid) {
- if (maxBidder != null && maxBidder != client) {
- maxBidder send BeatenOffer(bid)
- }
- maxBidder = client
- askedBid = bid + delta
- client send BestOffer
- } else client send BeatenOffer(maxBid)
- }
-\end{verbatim}
-\begin{verbatim}
- case Inquire(client) => {
- client send Status(askedBid, closing)
- }
-\end{verbatim}
-\begin{verbatim}
- case TIMEOUT => {
- if (maxBidder != null) {
- val reply = AuctionConcluded(seller, maxBidder)
- maxBidder send reply
- seller send reply
- } else seller send AuctionFailed
- receiveWithin (timeToShutdown) {
- case Offer(_, client) => client send AuctionOver ; discardAndContinue
- case _ => discardAndContinue
- case TIMEOUT => stop
- }
- }
-\end{verbatim}
-\begin{verbatim}
- case _ => discardAndContinue
- }
- }
- }
-\end{verbatim}
-\begin{verbatim}
- def houseKeeping: int = {
- val Limit = 100
- var nWaiting: int = 0
- receiveWithin(0) {
- case _ =>
- nWaiting = nWaiting + 1
- if (nWaiting > Limit) {
- receiveWithin(0) {
- case Offer(_, _) => continue
- case TIMEOUT =>
- case _ => discardAndContinue
- }
- } else continue
- case TIMEOUT =>
- }
- }
-}
-\end{verbatim}
-\begin{verbatim}
-class Bidder (auction: Process, minBid: int, maxBid: int)
- extends Process {
- val MaxTries = 3
- val Unknown = -1
-
- var nextBid = Unknown
-\end{verbatim}
-\begin{verbatim}
- def getAuctionStatus = {
- var nTries = 0
- while (nextBid == Unknown && nTries < MaxTries) {
- auction send Inquiry(this)
- nTries = nTries + 1
- receiveWithin(waitTime) {
- case Status(bid, _) => bid match {
- case None => nextBid = minBid
- case Some(curBid) => nextBid = curBid + Delta
- }
- case TIMEOUT =>
- case _ => continue
- }
- }
- status
- }
-\end{verbatim}
-\begin{verbatim}
- def bid: unit = {
- if (nextBid < maxBid) {
- auction send Offer(nextBid, this)
- receive {
- case BestOffer =>
- receive {
- case BeatenOffer(bestBid) =>
- nextBid = bestBid + Delta
- bid
- case AuctionConcluded(seller, client) =>
- transferPayment(seller, nextBid)
- case _ => continue
- }
-
- case BeatenOffer(bestBid) =>
- nextBid = nextBid + Delta
- bid
-
- case AuctionOver =>
-
- case _ => continue
- }
- }
- }
-\end{verbatim}
-\begin{verbatim}
- def run = {
- getAuctionStatus
- if (nextBid != Unknown) bid
- }
-
- def transferPayment(seller: Process, amount: int)
-}
-\end{verbatim}
-}
-%\todo{We also need some XML examples.}
-\end{document}
-
-
-
- case ([], _) => ys
- case (_, []) => xs
- case (x :: xs1, y :: ys1) =>
- if (x < y) x :: merge(xs1, ys) else y :: merge(xs, ys1)
-}
-
-def split (xs: List[a]): (List[a], List[a]) = xs match {
- case [] => ([], [])
- case [x] => (x, [])
- case y :: z :: xs1 => val (ys, zs) = split(xs1) ; (y :: ys, z :: zs)
-}
-
-def sort(xs: List[a]): List[a] = {
- val (ys, zs) = split(xs)
- merge(sort(ys), sort(zs))
-}
-
-
-def sort(a:Array[String]): Array[String] = {
- val pivot = a(a.length / 2)
- sort(a.filter(x => x < pivot)) ++
- a.filter(x => x == pivot) ++
- sort(a.filter(x => x > pivot))
-}
-
-def sort(a:Array[String]): Array[String] = {
-
- def swap (i: int, j: int): unit = {
- val t = a(i) ; a(i) = a(j) ; a(j) = t
- }
-
- def sort1(l: int, r: int): unit = {
- val pivot = a((l + r) / 2)
- var i = l, j = r
- while (i <= r) {
- while (i < r && a(i) < pivot) { i = i + 1 }
- while (j > l && a(j) > pivot) { j = j - 1 }
- if (i <= j) {
- swap(i, j)
- i = i + 1
- j = j - 1
- }
- }
- if (l < j) sort1(l, j)
- if (j < r) sort1(i, r)
- }
-
- sort1(0, a.length - 1)
-}
-
-class Array[a] {
-
- def copy(to: Array[a], src: int, dst: int, len: int): unit
- val length: int
- val apply(i: int): a
- val update(i: int, x: a): unit
-
- def filter (p: a => boolean): Array[a] = {
- val temp = new Array[a](a.length)
- var i = 0, j = 0
- for (i < a.length, i = i + 1) {
- val x = a(i)
- if (p(x)) { temp(j) = x; j = j + 1 }
- }
- val res = new Array[a](j)
- temp.copy(res, 0, 0, j)
- }
-
- def ++ (that: Array[a]): Array[a] = {
- val a = new Array[a](this.length + that.length)
- this.copy(a, 0, 0, this.length)
- that.copy(a, 0, this.length, that.length)
- }
-
-static
-
- def concat [a] (as: List[Array[a]]) = {
- val l = (as map (a => a.length)).sum
- val dst = new Array[a](l)
- var j = 0
- as forall {a => { a.copy(dst, j, a.length) ; j = j + a.length }}
- dst
- }
-
-}
-
-module ABT extends AlgBinTree[kt, vt]
-ABT.Map