metagear.de
1. Preface
These are solutions for the exercises in Martin Odersky's Scala By Example manual.
To my knowledge, official, or commonly approved, solutions do not exist. Moreover, only sporadically
have single, or few, solutions been published by third-party authors. The only (well, half-way)
comprehensive collection I'm aware of is the one provided by whiter4bbit . – In contrast, this article
covers any and every exercise.
Exercise 16.0.1, which is exceptionally hard, has been worked on by Nada Amin.
Most code samples in the article at hand are shortened for clarity. You can download the entire source
code , where every solution has a startable mainmethod and is usually accompanied by
corresponding unit tests.
Any feedback is appreciated and may be directed to robert.soeding@gmx.de. Should you solve any of
these exercises yourself and find your solutions more accurate or of another approach than mine, I'd
be grateful if you could send yours over.
Cheers
P.S.: Suspecting whether posting the solutions might be regarded a spoiler, I emailed Mr. Odersky
about that concern. – Well, he meant that publishing the article sounded like a good idea! – Kind, and
cool, thanks! – So here we go.
2. Exercises
2.1. Expressions and Simple Functions
2.1.1.1. Assignment
The isGoodEnoughtest is not very precise for small numbers and might lead to non-termination for very
large ones (why?). Design a different version of isGoodEnoughwhich does not have these problems.
2.1.1.2. Resolution
While the number of real numbers is infinite, the number of binary representable numbers is finite –
and so is the the number of floating-point numbers that the computer uses.
Floating point numbers can represent most real numbers by approximation only because there is no
exact binary representation. The "gap", or distance, between adjacent floating-point numbers is
smaller for small numbers, and becomes larger as the numbers increase (the larger its so-called
exponent becomes, actually). Thus, an absolute value (a distance of 0.001in the above code snippet)
cannot be used in general-purpose functions.
The solution is to use the scala.math.ulp(Double): Doublemethod – ulpmeaning, "units in the last
place", representing "the positive distance between this floating-point value and the doublevalue next
larger in magnitude".
For further information see a corresponding Wikipedia article on Accuracy Problems with Floating
Point Numbers , the article Floating Point Encoding (for understanding the distance between
floating-point numbers), the java.lang.MathApiDoc [1 ] [2 ], and a Scala-User mailing list thread,
on which this exercise gets discussed .
object Exercise_04_4_1 {
def sqrtIter(guess: Double, x: Double): Double =
if (isGoodEnough(guess, x)) guess
else sqrtIter(improve(guess, x), x)
Approximations
2.1.2.1. Assignment
2.1.2.2. Resolution
Using the improvemethod, guessgets successively approximated to the root of the sqrtfunction:
1.0
2.5
2.05
2.000609756097561
2.0000000929222947
2.000000000000002
2.0
See the following articles for more information: The Newton-Raphson Method , Newton's method
.
2.1.3.1. Assignment
2.1.3.2. Resolution
See the StackOverflow thread Use of recursion in Scala when run in the JVM for a further
discussion.
import annotation.tailrec
object Exercise_04_6_1 {
val emptyProduct = 1
if (n == 0) emptyProduct
else n * inefficientFactorial(n - 1)
}
factorial(n, em
ptyProduct)
}
assert(result0 == result1)
}
}
The @tailrecannotation causes the compiler to throw an error if the annotated method cannot be
compiled with tail-recursive optimizations (that is, re-structuring it to a loop).
2.2.1.1. Assignment
The sumfunction uses a linear recursion. Can you write a tail-recursive one by filling in the ??’s?
2.2.1.2. Resolution
import annotation.tailrec
assert(result0 == result1)
http://metagear.de/articles/scalaexercises/index.html#solution941a 4/25
17/10/2015 'Scala By Example' Exercises: Solutions
}
}
2.2.2.1. Assignment
Write a function productthat computes the product of the values of functions at points over a given
range.
2.2.2.2. Resolution
import annotation.tailrec
2.2.3.1. Assignment
2.2.3.2. Resolution
In my understanding, "in terms of product" means, computing "the product of the values of functions
at points over a given range" (see exercise 5.2.2). For a factorial, that range is half-fixed – its left
bound is its argument, and its right bound is 1. Beyond that difference, the productand factorial
equally compute the product of each integer within that range.
There is no solution because of contradictory task criteria; nevertheless, we can observe that product
equals a factorial except there are two variable (non-fixed) bounds, not one.
http://metagear.de/articles/scalaexercises/index.html#solution941a 5/25
17/10/2015 'Scala By Example' Exercises: Solutions
2.2.4.1. Assignment
Can you write an even more general function which generalizes both sumand product?
2.2.4.2. Resolution
2.2.5.1. Assignment
Given the following code, which contains the "fixed-point finding function" fixedPoint:
2.2.5.2. Resolution
object Exercise_05_3_1 {
def fixedPoint(f: Double => Double)(firstGuess: Double) = {
def iterate(guess: Double): Double = {
val next = f(guess)
iterate(firstGuess)
http://metagear.de/articles/scalaexercises/index.html#solution941a 6/25
17/10/2015 'Scala By Example' Exercises: Solutions
2.3.1.1. Assignment
trait IntSet {
def incl(x: Int): IntSet
def contains(x: Int): Boolean
}
class EmptyS
et extends IntS et {
def contains(x: Int): Boolean = false
def incl(x: Int): IntSet = new NonEmptySet(x, new EmptySet, new Em
ptySet)
}
Write methods unionand intersectionto form the union and intersection between two sets.
Add a method
to return the given set without the element x. To accomplish this, it is useful to also implement a test
http://metagear.de/articles/scalaexercises/index.html#solution941a 7/25
17/10/2015 'Scala By Example' Exercises: Solutions
method
for sets.
2.3.1.2. Resolution
trait IntSet {
def incl(x: Int): IntS
et
http://metagear.de/articles/scalaexercises/index.html#solution941a 8/25
17/10/2015 'Scala By Example' Exercises: Solutions
def incl(x: Int): IntSet =
if (x < elem) new NonEmptySet(elem, left incl x, right)
else if (x > elem) new NonEmptySet(elem, left, right incl x)
else this
2.3.2.1. Assignment
Write an implementation Integerof integer numbers. The implementation should support all
operations of class Nat:
http://metagear.de/articles/scalaexercises/index.html#solution941a 9/25
17/10/2015 'Scala By Example' Exercises: Solutions
def successor: Nat = new Succ(Zero)
def + (that: Nat): Nat = that
def - (that: Nat): Nat = if (that.isZero) Zero
else error("negative number")
}
The first method should return trueif 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 Integer. One can either make use the existing implementation of Nat,
representing an integer as a natural number and a sign. Or one can generalize the given
implementation of Natto Integer, using the three subclasses Zerofor 0, Succfor positive numbers and
Predfor negative numbers.)
2.3.2.2. Resolution
I have no idea how to implement a signed type in Scala, thus have implemented the other option
"only". – The toIntmethod does use one of Scala’s standard numeric classes, but it's just used for
testing purposes.
import annotation.tailrec
http://metagear.de/articles/scalaexercises/index.html#solution941a 10/25
17/10/2015 'Scala By Example' Exercises: Solutions
override def +(that: Integer): Integer = that
iter(posInt, negInt)
}
toInt(pred, 1)
}
}
http://metagear.de/articles/scalaexercises/index.html#solution941a 11/25
17/10/2015 'Scala By Example' Exercises: Solutions
toInt(pred, -1)
}
}
Jeremy Collins kindly pointed out that the above method of negating an integer (the method
posPlusNegInteger(..)) was unnecessarily complex (d'uh!) if we'd pass a related Integerto the
constructor (although I'm not sure whether the assignment allows that). – Here's his alternative
solution – thanks, Jeremy:
http://metagear.de/articles/scalaexercises/index.html#solution941a 12/25
17/10/2015 'Scala By Example' Exercises: Solutions
}
def negate: Integer = this
}
2.4.1.1. Assignment
Consider the following definitions representing trees of integers. These definitions can be seen as an
alternative representation of IntSet:
Complete the following implementations of function contains and insert for IntTree’s.
2.4.1.2. Resolution
class MyIntTree {
def contains(t: IntTree, v: Int): B
oolean = t match {
http://metagear.de/articles/scalaexercises/index.html#solution941a 13/25
17/10/2015 'Scala By Example' Exercises: Solutions
case EmptyTree => false
case Node(e, _, _) if e == v => true
case Node(e, l, _) if e < v => contains(l, v)
case Node(e, _, r) => contains(r, v)
}
/*
def contains(t: IntTree, v: Int): Boolean = t match {
case EmptyTree => false
case Node(elem: Int, left: IntTree, right: IntTree) =>
if (v == elem) true
else if (v < elem) contains(left, v)
else contains(right, v)
}
*/
There are two versions of the containsmethod, one of which featuring wildcard placeholders and
pattern guards.
Note that both functions, containsand insert– in contrast to our IntSet(see Exercises 6.0.1 and
6.0.2) – do not actually work (except for demonstrating Pattern Matching). To change that we'd need
to make the Node's properties accessible. Currently, they aren't because we're accessing the Nodes by
their IntTreeinterface (which we could change, etc. pp.). – Anyways, that's supposedly out of this
exercise's scope.
2.5. Lists
2.5.1.1. Assignment
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 insertion sort, which works as follows: To sort a non-
empty list with first element xand rest xs, sort the remainder xsand insert the element xat the right
position in the result. Sorting an empty list will yield the empty list. Expressed as Scala code:
2.5.1.2. Resolution
object Exercise_09_1_1 {
def isort(xs: List[Int]): List[Int] =
if (xs.isEmpty) Nil
else insert(xs.head, isort(xs.tail))
http://metagear.de/articles/scalaexercises/index.html#solution941a 14/25
17/10/2015 'Scala By Example' Exercises: Solutions
2.5.2.1. Assignment
2.5.2.2. Resolution
import annotation.tailrec
trait PimpedList[T]{
val xs: List[T]
iter(xs, 0)
}
}
object Exercise_09_2_1 {
implicit def toPimpedList[T](ys: List[T]) = new PimpedList[T] {
val xs = ys
}
http://metagear.de/articles/scalaexercises/index.html#solution941a 15/25
17/10/2015 'Scala By Example' Exercises: Solutions
The Listclass is sealedin Scala and thus cannot be extended. To work around that limitation ;-) ,
we're employing an implicit conversion to make the recursiveLengthmethod available to the List
instance.
2.5.3.1. Assignment
Consider a function which squares all elements of a list and returns a list with the results. Complete the
following two equivalent definitions of squareList.
2.5.3.2. Resolution
object Exercise_09_4_1 {
def squareList(xs: List[Int]): List[Int] = xs match {
case List() => List()
case y :: ys => math.pow(y, 2).toInt :: squareList(ys)
}
2.5.4.1. Assignment
http://metagear.de/articles/scalaexercises/index.html#solution941a 16/25
17/10/2015 'Scala By Example' Exercises: Solutions
2.5.4.2. Resolution
Bruce Gilmour of Lang Toun Software Ltd fixed a logical bug in the forallmethod. – Thanks
Bruce.
object Exercise_09_4_1_a {
def forall[A](p: A => Boolean)(xs: List[A]): Boolean = {
def filter[A](p: A => Boolean)(xs: List[A]): List[A] = xs match {
case Nil => Nil
case y :: ys =>
if (p(y)) y :: ys.filter(p)
else Nil
}
// filter(p)(xs).length > 0
filter(p)(xs).length == xs.length
}
filter(p)(xs).length > 0
}
2.5.5.1. Assignment
Consider the problem of writing a function flatten, which takes a list of element lists as arguments.
The result of flattenshould be the concatenation of all element lists into a single list. Here is an
implementation of this method in terms of :\.
http://metagear.de/articles/scalaexercises/index.html#solution941a 17/25
17/10/2015 'Scala By Example' Exercises: Solutions
What would be the difference in asymptotic complexity between the two versions of flatten?
2.5.5.2. Resolution
First-off, using curly braces ({}) vs. parentheses (()) does not make a difference. For clarity, let's also
name the functions accordingly:
The fold left method (/:, alias of foldLeft) and the fold right method (:\, alias for foldRight) (see
the ScalaDocs ) both take a start value ((Nil: List[A])in this case) and an operation ((x, xs)
=> x ::: xs, resp., (xs, x) => xs ::: xin this case).
The operation that both functions perform is list concatenation via the :::method.
For operations there is the concept of associativity, which defines on which object the function
operates, and which object(s) (if any) it takes as parameters. – Functions whose names end in a colon
(:) always associate to the right.
Hence /:operates on a filled Listin the above code snippet while :\operates on an empty one.
This defines the order of the parameters that are passed to the function that performs list
concatenation via :::.
As :::associates to the right (xs ::: xcan also be expressed as x.:::(xs)using the infix operator
.), the flattenLeftmethod needs to operate on the fully-filled (vs. initially empty) xs: Listat each
recursion. Considering the design of Scala Lists, this means that flattenLefthas to copy xs.headn -
1times, where nequals xs.length.
Thus, in this case, flattenRightought to be preferred because of the costly list concatenation,
because that associates right.
There's more to say on foldLeftand foldRight. For further information see Programming in
Scala – Second Edition, pp. 365 ff., and the following StackOverflow threads: [1 ] [2 ] [3 ].
2.5.6.1. Assignment
Fill in the missing expressions to complete the following definitions of some basic list-manipulation
operations as fold operations.
http://metagear.de/articles/scalaexercises/index.html#solution941a 18/25
17/10/2015 'Scala By Example' Exercises: Solutions
2.5.6.2. Resolution
object Exercise_09_4_3 {
def mapFun[A, B](xs: List[A], f: A => B): List[B]=
(xs :\ List[B]()) {
(x, xs) => f(x) :: xs
}
assert(lengthFun(xs) == 3)
assert(mapFun(xs, f) == List(1, 4, 9))
}
}
The articles Scala Code Review: foldLeft and foldRight and Lots And Lots Of foldLeft Examples
help digging deeper into foldLeftand foldRight.
2.6. For-Comprehensions
2.6.1.1. Assignment
Given a chess board of size n, place nqueens on it so that no queen is in check with another. –
Considering the code:
which tests whether a queen in the given column col is safe with respect to the queens already placed.
Here, delta is the difference between the row of the queen to be placed and the row of the first queen
in the list.
2.6.1.2. Resolution
Note that the queensfunction – in contrast to the n-Queens solution in Programming in Scala -
Second Edition, pp. 519 ff., – returns a List[List[Int]](i.e., List(List(3, 1, 4, 2), List(2, 4, 1,
3))for n = 4), where the position on the chess board is marked implicitly – as the order of the inner
list items (n - 1 to 0).
2.6.2.1. Assignment
2.6.2.2. Resolution
object Exercise_10_3_1 {
def flattenOrg[A](xss: List[List[A]]): List[A] =
(xss :\ (Nil: List[A]))((xs, ys) => xs ::: ys)
assert(flatten(xss) == flattenOrg(xss))
}
}
2.6.3.1. Assignment
Translate
to higher-order functions.
2.6.3.2. Resolution
object Exercise_10_3_2 {
http://metagear.de/articles/scalaexercises/index.html#solution941a 20/25
17/10/2015 'Scala By Example' Exercises: Solutions
val titles1 = for (b <- books; a <- b.authors if a startsWith "Bird") yield b.title
val titles2 = for (b <- books if (b.title indexOf "Program") >= 0) yield b.title
assert(titles1.length == 0)
assert(titles2.length == 3)
assert(titles1 == titles1a)
assert(titles2 == titles2a.reverse)
}
}
2.7.1.1. Assignment
http://metagear.de/articles/scalaexercises/index.html#solution941a 21/25
17/10/2015 'Scala By Example' Exercises: Solutions
com
mand; whileLoop(condition)(command)
} else ()
}
2.7.1.2. Resolution
object Exercise_11_2_1 {
def main(args: Array[String]) {
var x = 0
repeatLoop {x = x + 1} (x < 5)
assert(x == 5)
2.7.2.1. Assignment
Given the concepts bespoken in Scala by Example, pp. 92 ff., and the andGatemethod:
2.7.2.2. Resolution
http://metagear.de/articles/scalaexercises/index.html#solution941a 22/25
17/10/2015 'Scala By Example' Exercises: Solutions
def orGate(a1: Wire, a2: Wire, output: Wire) {
def orAction() {
val a1Sig = a1.getSignal
val a2Sig = a2.getSignal
afterDelay(OrGateDelay) {
output setSignal (a1Sig | a2Sig)
}
}
a1 addAction orAction
a2 addAction orAction
}
2.7.3.1. Assignment
and and-gates. Define a function orGatein terms of andGateand inverter. What is the delay time of
this function?
2.7.3.2. Resolution
In contrast to the original orGatefrom exercise 11.3.1, where the delay time is OrGateDelay, here the
delay time equals InverterDelay + AndGateDelay.
2.8.1.1. Assignment
Given the code introduced in Scala by Example, pp. 117 ff., extend the Mini-ML type inferencer with a
letrecconstruct which allows the definition of recursive functions. Syntax:
The typing of letrecis as for let, except that the defined identifier is visible in the defining expression.
http://metagear.de/articles/scalaexercises/index.html#solution941a 23/25
17/10/2015 'Scala By Example' Exercises: Solutions
Using letrec, the length function for lists can now be defined as follows.
2.8.1.2. Resolution
This is a highly complex assignment, which requires conceptual backgrounds on language design in
general and, particularly, on type inference – additionally, requiring outstanding logical skills and
efforts.
It appears to be not at all certain whether a resolution would have had been brought up if remarkably
exceptional Nada Amin had not provided one .
Please note that this solution may be work in progress. There may be future corrections to the
original assignment as well. – Thank you very much, Nada.
3. Resources
All links retrieved at the date of publication.
Alessi, Fabio: Type preorders and recursive terms (regarding the "fixed point operator fix,
which can be used to represent recursion"; also mentions the letrectyping rule (vs. let rec)),
Elsevier Science B. V., 2004
Elsman, Martin: A Portable Standard ML Implementation , Technical University of Denmark,
1994
Fix, Jim: Homework 7: MiniML type inference (assignment), people.reed.edu, 2010
Fix, Jim: Homework 7: MiniML type inference (template code in Scala – unfortunately, using
Scala 2.9, throws a runtime error with the basic sample it ships), people.reed.edu, 2010
Fix, Jim: The MiniML Programming Language (with substitution semantics) , people.reed.edu,
2010
Forrest, Andrew: Hindley-Milner type inference in Scala (implementation similar to Odersky's –
unfortunately, throws a runtime error with Scala 2.9, but works with 2.7.7), dysphoria.net, 2009
Khamsi, Mohamed A.; Knaust, Helmut: The Newton-Raphson Method , www.sosmath.com, 201
Wikimedia Foundation, Inc. (Edt.): ML (programming language) , en.wikipedia.org, 2011
Wikimedia Foundation, Inc. (Edt.): Newton's method , en.wikipedia.org, 2011
http://metagear.de/articles/scalaexercises/index.html#solution941a 25/25