Professional Documents
Culture Documents
2.immutable Lists - Reading 2 - Recursive Data Types - 6.005.2x Courseware - Edx
2.immutable Lists - Reading 2 - Recursive Data Types - 6.005.2x Courseware - Edx
2x Courseware | edX
Immutable lists
Introduction
In this reading we'll look at recursively-de ned types, how to specify operations on
such types, and how to implement them. Our main example will be immutable lists.
Then we'll use another recursive datatype example, matrix multiplications, to walk
through our process for programming with ADTs.
Recursive functions
Before we introduce recursive datatypes — which have a recursive structure of both
data and computation — take a minute to review recursive computations.
Immutable lists
We'll start with a classic recursive datatype, the immutable list.
Immutability is powerful not just because of its safety, but also because of the potential
for sharing. Sharing actually produces performance bene ts: less memory consumed,
less time spent copying. Here we're going to look at how to represent list data
structures di erently than in our familiar array lists or linked lists.
Let's de ne a data type for an immutable list, ImList<E>. The data type has four
fundamental operations:
https://courses.edx.org/courses/course-v1:MITx+6.005.2x+1T2017/courseware/Readings/02-Recursive-Data-Types/?child=first 1/8
5/10/2020 Immutable lists | Reading 2: Recursive Data Types | 6.005.2x Courseware | edX
// returns the list of all elements of this list except for the rst,
rest: ImList → ImList
requires the list to be nonempty
These four operations have a long and distinguished pedigree. They are fundamental
to the list-processing languages Lisp and Scheme (where for historical reasons they are
called nil, cons, car, and cdr, respectively). They are widely used in functional
programming, where you can often nd them called head and tail instead of rst and
rest.
Before we design Java classes to implement this datatype, let's get used to the
operations a bit, using lists of integers. We'll write lists with square brackets, like [ 1, 2,
3 ], and we'll write the operations as if they are mathematical functions. Once we get to
Java, the syntax will look di erent but the operations will have the same meaning.
https://courses.edx.org/courses/course-v1:MITx+6.005.2x+1T2017/courseware/Readings/02-Recursive-Data-Types/?child=first 2/8
5/10/2020 Immutable lists | Reading 2: Recursive Data Types | 6.005.2x Courseware | edX
empty() = [ ]
cons(0, empty() ) = [ 0 ]
rst(x) = 0
rest(x) = [ 1, 2 ]
rst(rest(x) ) = 1
rest(rest(x) ) = [ 2 ]
rst(rest(rest(x) ) = 2
rest(rest(rest(x) ) ) = [ ]
What cons puts together, rst and rest peel back apart.
T
public interface ImList<E> {
h
public static ImList<E> empty(); // not quite right yet, see below
is
public ImList<E> cons(E e);
public E first(); i
public ImList<E> rest(); n
} t
https://courses.edx.org/courses/course-v1:MITx+6.005.2x+1T2017/courseware/Readings/02-Recursive-Data-Types/?child=first 3/8
5/10/2020 Immutable lists | Reading 2: Recursive Data Types | 6.005.2x Courseware | edX
e
rface declares a generic type ImList<E> that can be instantiated for any type E:
ImList<Integer>, ImList<String>, etc. The E in these declarations is a placeholder
that the compiler will ll in when it checks our code for type safety.
Empty represents the result of the empty operation (an empty list)
Cons represents the result of a cons operation (an element glued together with
another list)
https://courses.edx.org/courses/course-v1:MITx+6.005.2x+1T2017/courseware/Readings/02-Recursive-Data-Types/?child=first 4/8
5/10/2020 Immutable lists | Reading 2: Recursive Data Types | 6.005.2x Courseware | edX
So we have methods for cons, rst, and rest, but where is the fourth operation of our
datatype, empty?
One way to implement empty is to have clients call the Empty class constructor to
obtain empty lists. This sacri ces representation independence — clients have to know
about the Empty class!
Perhaps someday Java will o er a List.empty() method to obtain new empty Lists,
but not yet.
We will go ahead and update our ImList interface with the static empty method:
https://courses.edx.org/courses/course-v1:MITx+6.005.2x+1T2017/courseware/Readings/02-Recursive-Data-Types/?child=first 5/8
5/10/2020 Immutable lists | Reading 2: Recursive Data Types | 6.005.2x Courseware | edX
Now that we have all the operations, here's some actual Java code that parallels the
abstract examples we wrote earlier.
x.first() rst(x) 0
x.rest() rest(x) [ 1, 2 ]
x.rest().first() rst(rest(x)) 1
x.rest().rest().first() rst(rest(rest(x))) 2
x.rest().rest().rest() rest(rest(rest(x))) []
https://courses.edx.org/courses/course-v1:MITx+6.005.2x+1T2017/courseware/Readings/02-Recursive-Data-Types/?child=first 6/8
5/10/2020 Immutable lists | Reading 2: Recursive Data Types | 6.005.2x Courseware | edX
The key thing to note here is the sharing of structure that immutable list provides. In the
last example above, x and y are sharing their representation of the sublist [ 1, 2 ].
For ImList, the two implementations Empty and Cons cooperate in order to implement
the datatype — you need them both.
Generics usage 10
I wonder if it would be a mistake if I wrote: ImList<Integer> nil = ImList.<Integer>empty(); instead …
elt? lst?
3
rst(cons(elt, lst) ) = elt rest(cons(elt, lst) ) = lst what do elt and lst mean in those two equations?
https://courses.edx.org/courses/course-v1:MITx+6.005.2x+1T2017/courseware/Readings/02-Recursive-Data-Types/?child=first 7/8
5/10/2020 Immutable lists | Reading 2: Recursive Data Types | 6.005.2x Courseware | edX
https://courses.edx.org/courses/course-v1:MITx+6.005.2x+1T2017/courseware/Readings/02-Recursive-Data-Types/?child=first 8/8