Lists are probably the most commonly used data structure in Scala
programs. This chapter explains lists in detail. It presents many
common operations that can be performed on lists. It also teaches some
important design principles for programs working on lists.

Lists are quite similar to arrays, but there
are two important differences. First, lists are immutable. That
is, elements of a list cannot be changed by assignment. Second,
lists have a recursive structure (i.e., a linked
list),[1]
whereas arrays are flat.

Like arrays, lists are homogeneous: the elements of a
list all have the same type. The type of a list that has elements of type
T is written List[T]. For instance, here are the same four lists
with explicit types added:

The list type in Scala is covariant. This means
that for each pair of types S and T, if S is a subtype of T, then
List[S] is a subtype of List[T]. For instance, List[String]
is a subtype of List[Object]. This is natural because every list of
strings can also be seen as a list of
objects.[2]

Note that the empty list has type
List[Nothing]. You saw in Section 11.3
that Nothing is the bottom type in Scala's class hierarchy. It
is a subtype of every other Scala type.
Because lists are covariant, it follows that List[Nothing] is a subtype of List[T],
for any type T. So the empty list object, which has type List[Nothing],
can also be seen as an object of every other list type of the form List[T].
That's why it is permissible to write code like:

All lists are built from two fundamental building blocks, Nil
and :: (pronounced "cons").Nil represents the empty
list. The infix operator, ::, expresses list extension at the front. That is,
x::xs represents a list whose first element is x, followed by (the elements of) list xs. Hence, the previous
list values could also have been defined as follows:

All operations on lists can be expressed in terms of the following
three:

head

returns the first element of a list

tail

returns a list consisting of all elements except the first

isEmpty

returns true if the list is empty

These operations are defined as methods of class List.
Some examples are shown in Table 16.1.

Table 16.1 - Basic list operations

What it is

What it does

empty.isEmpty

returns true

fruit.isEmpty

returns false

fruit.head

returns "apples"

fruit.tail.head

returns "oranges"

diag3.head

returns List(1,0,0)

The head and tail methods are defined only for non-empty
lists. When selected from an empty list, they throw an exception. For instance:

scala> Nil.head
java.util.NoSuchElementException: head of empty list

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 x::xs, sort
the remainder xs and insert the first element x at the right
position in the result. Sorting an empty list yields the
empty list. Expressed as Scala code, the insertion sort algorithm looks like:

Lists can also be taken apart using pattern matching. List patterns
correspond one-by-one to list expressions. You can either match on all
elements of a list using a pattern of the form List(...), or you
take lists apart bit by bit using patterns composed from the
:: operator and the Nil constant.

The pattern List(a, b, c) matches lists of length 3, and binds the three elements
to the pattern variables a, b, and c.
If you don't know the number of list elements beforehand, it's better to match with
:: instead. For instance, the pattern a::b::rest
matches lists of length 2 or greater:

About pattern matching on Lists

If you review the possible forms of patterns explained in
Chapter 15, you might find that neither List(...) nor
:: looks like it fits one of the kinds of patterns defined there.
In fact, List(...) is an instance of a library-defined
extractor pattern.
Such patterns will be treated in Chapter 24.
The "cons" pattern x::xs is a special case of an infix operation pattern.
You know already that, when seen as an expression, an infix operation is equivalent to a method call.
For patterns, the rules are different: When seen as a pattern, an infix operation
such as popq is equivalent to op(p,q). That is, the infix operator
op is treated as a constructor pattern. In particular, a cons pattern such as x::xs is
treated as ::(x,xs). This hints that there should be a class named :: that
corresponds to the pattern constructor. Indeed there is such as class. It is named
scala.:: and is exactly the class that builds non-empty lists. So :: exists twice
in Scala, once as a name of a class in package scala, and again
as a method in class List. The effect of the method :: is to produce an
instance of the class scala.::. You'll find out more details about how the List class
is implemented in Chapter 22.

Taking lists apart with patterns is an alternative to taking them apart with
the basic methods head, tail, and isEmpty. For instance, here's insertion sort again,
this time written with pattern matching:

Often, pattern matching over lists is clearer than decomposing them with methods,
so pattern matching should be a part of your list processing toolbox.

This is all you need to know about lists in Scala to be able to use
them correctly. However, there are also a large number of methods
that capture common patterns of operations over lists.
These methods make list processing programs more concise
and often clearer. The next two sections present the most
important methods defined in the List class.

This section explains most first-order methods defined in the List
class. A method is first-order if it does not take any functions as
arguments. The section also introduces by means of two examples some
recommended techniques to structure programs that operate on lists.

Concatenating lists

An operation similar to :: is list concatenation, written
`:::'. Unlike ::, ::: takes two lists as
operands.
The result of xs:::ys is a new list that contains all the elements
of xs, followed by all the elements of ys. Here are some examples:

Like cons, list concatenation associates to the right. An expression like this:

xs ::: ys ::: zs

is interpreted like this:

xs ::: (ys ::: zs)

The Divide and Conquer principle

Concatenation (:::) is implemented as a method in class List. It
would also be possible to implement concatenation "by hand," using
pattern matching on lists. It's instructive to try to do that
yourself, because it shows a common way to implement algorithms using lists. First, we'll settle on a signature for the concatenation
method, which we'll call append. In order not to mix things up too much, assume that
append is defined outside the List class. So it will take the two
lists to be concatenated as parameters. These two lists
must agree on their element type,
but that element type can be arbitrary. This can be expressed by giving
append a type parameter[3] that represents the element type of the
two input lists:

def append[T](xs: List[T], ys: List[T]): List[T]

To design the implementation of append, it pays to remember the
"divide and conquer" design principle for programs over recursive
data structures such as lists. Many algorithms over lists first split
an input list into simpler cases using a pattern match. That's the
divide part of the principle. They then construct a result for
each case. If the result is a non-empty list, some of its parts may be
constructed by recursive invocations of the same algorithm. That's the
conquer part of the principle.

To apply this principle to the implementation of the append method,
the first question to ask is on which list to
match. This is less trivial in the case of append
than for many other methods because there
are two choices. However, the subsequent "conquer" phase tells you
that you need to construct a list consisting of all elements of both
input lists. Since lists are constructed from the back towards the front, ys can
remain intact whereas xs will need to be taken apart and prepended to ys. Thus, it makes sense to concentrate on
xs as a source for a pattern match. The most common pattern
match over lists simply distinguishes an empty from a non-empty
list. So this gives the following outline of an append method:

All that remains is to fill in the two places marked with "??".
The first such place is the alternative where the input list xs is empty.
In this case concatenation yields the second list:

caseList() => ys

The second place left open is the alternative where the input list xs
consists of some head x followed by a tail xs1. In this
case the result is also a non-empty list. To construct a non-empty list
you need to know what the head and the tail of that list should be.
You know that the first element of the result list is x.
As for the remaining elements, these can be computed by appending
the rest of the first list,
xs1, to the second
list ys. This completes the design and gives:

The computation of the second alternative illustrated the "conquer" part of the
divide and conquer principle:
Think first what the shape of the desired output should be,
then compute the individual parts of that shape, using recursive invocations
of the algorithm where appropriate. Finally, construct the output
from these parts.

Taking the length of a list: length

The length method computes the length of a list.

scala> List(1, 2, 3).length
res3: Int = 3

On lists, unlike arrays, length is a relatively expensive operation.
It needs to traverse the whole list to find its end
and therefore takes time proportional to the number of elements in the list.
That's why it's not a good idea to replace a test such as
xs.isEmpty by xs.length==0. The result of the two tests are equivalent, but
the second one is slower, in particular if the list xs is long.

Accessing the end of a list: init and last

You know already the basic operations head and tail, which
respectively take the first element of a list, and the rest of the
list except the first element. They each have a dual operation:last returns the last element of a (non-empty) list, whereas
init returns a list consisting of all elements except the last one:

Unlike head and tail, which both run in constant time, init and last
need to traverse the whole list to compute their result. They
therefore take time proportional to the length of the list.

It's a good idea to organize your data so that
most accesses are at the head of a list, rather than the last element.

Reversing lists: reverse

If at some point in the computation an algorithm demands frequent
accesses to the end of a list, it's sometimes better to reverse the
list first and work with the result instead. Here's how to do the reversal:

scala> abcde.reverse
res6: List[Char] = List(e, d, c, b, a)

Note that, like all other list operations, reverse creates a new
list rather than changing the one it operates on. Since lists are
immutable, such a change would not be possible, anyway. To verify
this, check that the original value of abcde is unchanged after the
reverse operation:

scala> abcde
res7: List[Char] = List(a, b, c, d, e)

The reverse, init, and last operations satisfy some
laws which can be used for reasoning about computations and for
simplifying programs.

reverse is its own inverse:

xs.reverse.reverse equals xs

reverse turns init to tail and last to head,
except that the elements are reversed:

However, this method is less efficient than one would hope for. To
study the complexity of rev, assume that the list xs has length
n. Notice that there are n recursive calls to rev. Each
call except the last involves a list concatenation. List concatenation
xs:::ys takes time proportional to the length of its first
argument xs. Hence, the total complexity of rev is:

n + (n - 1) + ... + 1 = (1 + n) * n / 2

In other words, rev's complexity is quadratic in the length of its input
argument. This is disappointing when compared to the standard
reversal of a mutable, linked list, which has linear
complexity. However, the current implementation of rev is not the
best implementation possible. You will see in Section 16.7 how to speed it up.

Prefixes and suffixes: drop, take and splitAt

The drop and take operations generalize tail and init in that they
return arbitrary prefixes or suffixes of a list.
The expression "xstaken" returns the
first n elements of the list xs.
If n is greater than xs.length, the whole list xs is returned.
The operation "xsdropn" returns all elements of the list xs
except the first n ones.
If n is greater than xs.length, the empty list is returned.

The splitAt operation splits the list at a given index, returning
a pair of two lists.[4]
It is defined by the equality:

xssplitAtnequals(xstaken,xsdropn)

However, splitAt avoids traversing the list xs twice.
Here are some examples of these three methods:

Element selection: apply and indices

Random element selection is supported through the apply method; however
it is a less common operation for lists than it
is for arrays.

scala> abcde apply 2// rare in Scalares11: Char = c

As for all other types, apply is implicitly inserted
when an object appears in the function position in a method call,
so the line above can be shortened to:

scala> abcde(2) // rare in Scalares12: Char = c

One reason why random element selection is less popular
for lists than for arrays is that xs(n) takes time proportional
to the index n. In fact, apply is simply
defined by a combination of drop and head:

xsapplynequals(xsdropn).head

This definition also makes clear that list indices range from
0 up to the length of the list minus one, the same as for arrays. The indices method
returns a list consisting of all valid indices of a given list:

Displaying lists: toString and mkString

The toString operation returns the canonical string representation
of a list:

scala> abcde.toString
res16: String = List(a, b, c, d, e)

If you want a different representation you can use the mkString
method. The operation xsmkString(pre,sep,post) involves four
operands:
the list xs to be displayed, a prefix string pre to be
displayed in front of all elements, a separator string sep to be displayed
between successive elements, and a postfix string post to be
displayed at the end. The result of the operation is the string:

pre+xs(0)+sep+ ...+sep+xs(xs.length-1)+post

The mkString method has two overloaded variants that let you drop
some or all of its arguments. The first variant only takes a separator
string:

Example: Merge sort

The insertion sort presented earlier is concise to write, but
it is not very efficient. Its average complexity is proportional to the
square of the length of the input list. A more efficient algorithm
is merge sort.

The fast track

This example provides another illustration of the divide and conquer principle and currying, as well as a useful discussion of algorithmic complexity. If you
prefer to move a bit faster on your first pass through this book, however, you can safely skip to Section 16.7.

Merge sort works as follows: First, if the list has zero or one elements, it is already sorted, so
the list can be returned 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, you want to leave open
the type of list elements to be sorted, and also want to leave open the function to be
used for the comparison of elements. You obtain a function of maximal
generality by passing these two items as parameters. This leads to the
implementation shown in Listing 16.1.

Listing 16.1 - A merge sort function for Lists.

The complexity of msort is order (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 msort
halves the number of elements in its input, so there are about 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
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 n. Since there are
log(n) call levels, we obtain an overall cost proportional to
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 property makes merge sort an attractive algorithm for
sorting lists.

The intSort variable refers to a function that takes a list of integers and sorts them in numerical order.
As described in Section 8.6,
an underscore stands for a missing argument list. In this
case, the missing argument is the list that should be sorted. As another example, here's
how you could define a function that sorts a list of integers in reverse numerical order:

Many operations over lists have a similar structure. Several patterns
appear time and time again. Some examples are:
transforming every element of a list in some way,
verifying whether a property holds for all elements of a list,
extracting from a list elements satisfying a certain criterion, or
combining the elements of a list using some operator. In Java, such patterns would usually be expressed by idiomatic
combinations of for or while loops. In Scala, they can be
expressed more concisely and directly using higher-order operators,[6]
which are implemented as methods in class List. These higher-order operators are
discussed in this section.

Mapping over lists: map, flatMap and foreach

The operation xsmapf
takes as operands a list xs of type List[T]
and a function f of type T=>U. It returns the list resulting
from applying the function f to each list element in xs. For instance:

The flatMap operator is similar to map, but it takes a function
returning a list of elements as its right operand. It applies the
function to each list element and returns the concatenation of all function
results. The difference between map and flatMap is illustrated
in the following example:

List.range is a utility method that creates a list
of all integers in some range. It is used twice in this
example: once to generate a list of integers from 1 (including) until 5 (excluding),
and in a second time to generate a list of integers from 1
until i, for each value of i taken from the first list.
The map in this expression
generates a list of tuples (i, j) where j < i.
The outer
flatMap in this example generates this list for each i between
1 and 5, and then concatenates all the results.

Note that the same list can alternatively be constructed with a for expression:

for (i <- List.range(1, 5); j <- List.range(1, i)) yield (i, j)

You'll learn more about the interplay of for expressions and list operations in
Chapter 23.

The third map-like operation is foreach. Unlike map
and flatMap, however, foreach takes a procedure (a function with result type
Unit) as right operand. It simply applies the procedure to each
list element. The result of the operation itself is again Unit; no
list of results is assembled. As an example, here is a concise way of
summing up all numbers in a list:

The partition method is like filter, but it returns a pair of lists.
One list contains all elements for which the predicate is true, while the other
list contains all elements for which the predicate is false.
It is defined by the equality:

The find method is also similar to filter but it returns the
first element satisfying a given predicate, rather than all such elements.
The operation xsfindp takes a list xs and a predicate p as
operands. It returns an optional value. If there is an element x
in xs for which p(x) is true, Some(x) is returned. Otherwise,
p is false for all elements, and None is returned.
Here are some examples:

The takeWhile and dropWhile operators also take a predicate as
their right operand. The operation xstakeWhilep takes the longest prefix of list
xs such that every element in the prefix satisfies p.
Analogously, the operation xsdropWhilep removes the longest prefix from list
xs such that every element in the prefix satisfies p. Here are some examples:

Predicates over lists: forall and exists

The operation xsforallp takes as arguments a list xs and a
predicate p. Its result is true if all elements in the list
satisfy p. Conversely, the operation xsexistsp returns true
if there is an element in xs that satisfies the predicate p. For
instance, to find out whether a matrix represented as a list of lists
has a row with only zeroes as elements:

A fold left operation "(z/:xs)(op)" involves three objects:
a start value z, a list xs, and a binary operation op.
The result of the fold is op applied between successive
elements of the list prefixed by z. For instance:

(z/:List(a,b,c))(op)equalsop(op(op(z,a),b),c)

Or, graphically:

Here's another example that illustrates how /: is used. To concatenate all
words in a list of strings with spaces between them and in front, you
can write this:

The /: operator produces left-leaning operation trees (its syntax
with the slash rising forward is intended to be a reflection of that).
The operator has :\ as an analog that produces right-leaning
trees. For instance:

(List(a,b,c):\z)(op)equalsop(a,op(b,op(c,z)))

Or, graphically:

The :\ operator is pronounced fold right.
It involves the same three operands as fold left, but the first two
appear in reversed order: The first operand is the list to
fold, the second is the start value.

For associative operations, fold left and fold right are
equivalent, but there might be a difference in efficiency.
Consider for instance an operation corresponding
to the List.flatten method, which
concatenates all
elements in a list of lists.[7] This could be implemented with either
fold left or fold right:

Because list concatenation, xs:::ys, takes time proportional to its
first argument xs, the implementation in terms of fold right in
flattenRight is more efficient than the fold left implementation in
flattenLeft. The problem is that flattenLeft(xss) copies the first
element list xss.headn-1 times, where n is the length of the
list xss.

Note that both versions of flatten require a type annotation
on the empty list that is the start value of the fold.
This is due to a limitation in Scala's type
inferencer, which fails to infer the correct type of the list
automatically. If you try to leave out the annotation, you get the
following:

To find out why the type inferencer goes wrong, you'll need to know
about the types of the fold methods and how they are implemented. More
on this in Chapter 22.
Lastly, although the /: and :\ operators have the advantage that the direction
of the slash resembles the graphical depiction of their respective left or right-leaning trees, and the associativity of
the colon character places the start value in the same position in the
expression as it is in the tree, some may find the resulting code less than intuitive. If you prefer, you can alternatively
use the methods named foldLeft
and foldRight, which are also defined on class List.

Example: List reversal using fold

Earlier in the chapter you saw an implementation of method
reverse, named rev, whose running time was quadratic in the length of the list
to be reversed. Here is now a different implementation of reverse
that has linear cost. The idea is to use a fold left
operation based on the following scheme:

def reverseLeft[T](xs: List[T]) = (startvalue /: xs)(operation)

It only remains to fill in the startvalue and operation parts. In fact, you can
try to deduce these parts from some simple examples. To deduce the correct
value of startvalue, you can start with the smallest possible list, List(), and
calculate as follows:

List()
equals(by the properties of reverseLeft) reverseLeft(List())
equals(by the template for reverseLeft) (startvalue /: List())(operation)
equals(by the definition of /:)startvalue

Hence, startvalue must be List(). To deduce the second operand, you can
pick the next smallest list as an example case. You know already that
startvalue is List(), so you can calculate as follows:

Hence, operation(List(),x) equals List(x), which can also be written
as x::List(). This suggests taking as operation the
:: operator with its operands exchanged. (This operation is
sometimes called "snoc," in reference to ::, which is
called cons.) We arrive then at
the following implementation for reverseLeft:

(Again, the type annotation in List[T]() is necessary to make the
type inferencer work.) If you analyze the complexity of reverseLeft,
you'll find that it applies a constant-time operation ("snoc") n
times, where n is the length of the argument list. Hence, the
complexity of reverseLeft is linear, as hoped for.

Sorting lists: sort

The operation xssortbefore, where "xs" is a list and
"before" is a function that can be used to compare two elements,
sorts the elements of list xs.
The expression xbeforey should return
true if x should come before y in the intended ordering for the sort.
For instance:

So far, all operations you have seen in this chapter are implemented
as methods of class List, so you invoke them on individual list
objects. There are also a number of methods in the globally accessible
object scala.List, which is the companion object of class List.
Some of these operations are factory methods that create lists.
Others are operations that work on lists of some specific shape.
Both kinds of methods will be presented in this section.

Creating lists from their elements: List.apply

You've already seen on several occasions list literals such as
List(1,2,3).
There's nothing special about their syntax. A literal like
List(1,2,3) is simply the application of the object List to
the elements 1, 2, 3. That is, it is equivalent to List.apply(1,2,3):

scala> List.apply(1, 2, 3)
res50: List[Int] = List(1, 2, 3)

Creating a range of numbers: List.range

The range method, which you saw briefly earlier in the chapter in the discussion of map and flatmap,
creates a list consisting of a range of numbers.
Its simplest form is List.range(from,until), which creates a list of all
numbers starting at from and going up to until minus one. So the
end value, until, does not form part of the range.

There's also a version of range that takes a step value as
third parameter. This operation will yield list elements
that are step values apart, starting at from. The step can be positive
or negative:

Unzipping lists: List.unzip

The unzip operation is the inverse of zip. Where zip takes two lists
and forms a list of pairs, unzip takes a list of pairs and
returns two lists, one consisting of the first element of each pair,
the other consisting of the second element:

Note

You might wonder why unzip
is a method of the global List object, instead of being a method
of class List. The problem is that unzip does not work on any list
but only on a list of pairs, whereas Scala's type system requires every method
of a class to be available on every instance of that class.
Thus, unzip cannot go in the List class.
It might be possible to extend Scala's type system in the future so that it
accepts methods that only apply to some instances of a class, but so far
this has not been done.

Concatenating lists: List.flatten, List.concat

The flatten method takes a list of lists and concatenates all
element lists of the main list. For example:

Note

The flatten method is packaged in the global List object for the same reason as unzip:
it does not operate on any list, but only on lists with lists as elements,
so it can't be a method of the generic List class.

The concat method is similar to flatten in that it concatenates
a number of element lists. The element lists are given directly
as repeated parameters. The number of lists to be passed to concat is arbitrary:

The map2 method is similar to map, but it takes two lists as arguments together
with a function that maps two element values to a result. The function
gets applied to corresponding elements of the two lists, and a list is formed from the results:

The exists2 and forall2 methods are similar to exists and forall,
respectively, but they also take two lists and a boolean predicate that takes
two arguments. The predicate is applied to corresponding arguments:

The fast track

In the next (and final) section of this chapter, we provide insight into Scala's type inference algorithm. You can safely
skip the entire section if you're not interested in such details right now, and instead go straight to the conclusion
here.

The two expressions are equivalent, but the first uses a
longer form of comparison function with named parameters and explicit types whereas
the second uses the concise form, (_>_), where named
parameters are replaced by underscores. Of course, you could
also use the first, longer form of comparison with sort.
However, the short form cannot be used with msort:

To understand why, you need to know some details of Scala's type inference algorithm.
Type inference in Scala is flow based. In a method application m(args),
the inferencer first checks whether the method m has a known type.
If it has, that type is used to infer the expected type of the arguments.
For instance, in abcde.sort(_>_), the type of abcde is List[Char],
hence sort is known to be a method that takes an argument
of type (Char,Char)=>Boolean and produces a result of type List[Char].
Since the parameter types of the function arguments are thus
known, they need not be written explicitly.
With what it knows about sort, the inferencer can deduce
that (_>_) should expand to ((x:Char,y:Char)=>x>y) where
x and y are some arbitrary fresh names.

Now consider the second case, msort(_>_)(abcde).
The type of msort is a curried, polymorphic method type
that takes an argument of type (T,T)=>Boolean to a function from
List[T] to List[T]where T is some as-yet unknown type.
The msort method needs to be instantiated with a type parameter
before it can be applied to its arguments.
Because the precise instance type of msort in the application is not yet known,
it cannot be used to infer the type of its first argument.
The type inferencer changes its strategy
in this case; it first type checks method arguments to determine
the proper instance type of the method. However, when tasked to
type check the short-hand function literal, (_>_), it fails because it
has no information about the
types of the implicit function parameters that are indicated by underscores.

One way to resolve the problem is to pass an explicit type
parameter to msort, as in:

What has happened is that the inferencer used the known type of
the first parameter abcde to determine the type
parameter of msortSwapped. Once the precise type of msortSwapped was known,
it could be used in turn to infer the type of the second parameter, (_>_).

Generally, when tasked to infer the type parameters of a polymorphic
method, the type inferencer consults the types of all value arguments
in the first parameter list but no arguments beyond
that. Since msortSwapped is a curried method with two parameter lists,
the second argument (i.e., the function value) did not need to be consulted
to determine the type parameter of the method.

This inference scheme suggests the following library design principle:
When designing a polymorphic method that takes some non-function
arguments and a function argument, place the function argument last in a
curried parameter list by its own. That way, the method's correct
instance type can be inferred from the non-function arguments, and
that type can in turn be used to type check the function argument. The
net effect is that users of the method will be able to give less type
information and write function literals in more compact ways.

Now to the more complicated case of a fold operation.
Why is there the need for an explicit type parameter in an expression like
the body of the flattenRight method shown previously?

(xss :~List[T]()) (_ ::: _)

The type of the fold-right operation is polymorphic in two type variables.
Given an expression:

(xs :~z) (op)

The type of xs must be a list of some arbitrary type A,
say xs:List[A]. The start value z can be of some other type B.
The operation op must then take two arguments of type A and B
and must return a result of type B, i.e., op:(A,B)=>B.
Because the type of z is not related to the type of the list
xs, type inference has no context information for z.
Now consider the erroneous expression in the method flattenRight above:

(xss :~List()) (_ ::: _) // this won't compile

The start value z in this fold is an empty list, List(),
so without additional type information its type is inferred to
be a List[Nothing].
Hence, the inferencer will infer that the B type of the fold is
List[Nothing]. Therefore, the operation (_:::_) of the fold
is expected to be of the following type:

(List[T], List[Nothing]) => List[Nothing]

This is indeed a possible type for the operation in that fold but it
is not a very useful one! It says that the operation always takes an
empty list as second argument and always produces an empty list as
result. In other words, the type inference settled too early on a
type for List(), it should have waited until it had seen
the type of the operation op. So the (otherwise very useful) rule
to only consider the first argument section in a curried method
application for determining the method's type is at the root of the
problem here. On the other hand, even if that rule were relaxed, the
inferencer still could not come up with a type for op because its
parameter types are not given. Hence, there is a Catch-22
situation which can only be resolved by an explicit type annotation
from the programmer.

This example highlights some limitations of the local, flow-based type
inference scheme of Scala. It is not present in the more global
Hindley-Milner style of type inference used in functional
languages such as ML or
Haskell. However, Scala's local type inference
deals much more gracefully with object-oriented subtyping than the
Hindley-Milner style does. Fortunately, the
limitations show up only in some corner cases, and are usually easily
fixed by adding an explicit type annotation.

Adding type annotations is also a useful debugging technique when you
get confused by type error messages related to polymorphic methods. If
you are unsure what caused a particular type error, just add some type
arguments or other type annotations, which you think are correct. Then
you should be able to quickly see where the real problem is.

Now you have seen many ways to work with lists. You have seen the
basic operations like head and tail, the first-order operations
like reverse, the higher-order operations like map, and the
utility methods in the List object. Along the way, you
learned a bit about how Scala's type inference works.

Lists are a real work horse in Scala, so you will benefit from knowing
how to use them. For that reason, this chapter has delved deeply into
how to use lists. Lists are just one kind of collection that Scala
supports, however. The next chapter is broad, rather than deep, and
shows you how to use a variety of Scala's collection types.