Using our original list representation, where the empty list is represented by the null reference null, the previous code would never be used to create a string from an empty list.
The reason is that the null reference does not represent an actual object.
Java does not allow any method to be applied relative to the null reference, since there is no object there.
This creates an annoyance for treating lists as objects; the empty list has to be treated unsymmetrically.
For this reason, we might prefer a slightly different list representation, where a list is represented as an object which is a "handle" to the first cell, rather than just a plan reference to the first cell.
In this new model, there are two class of objects used:
List: representing the list
Cell: representing the cell of a list
List Representation so Far
(the empty list would be the null reference)
List Objects as Handles (shown in red)
The empty List as an Object
Here is the way we would structure the definitions, which are still quite similar to the original.
class StringList{StringCell handle;
static String first(StringList L){return handle.first;}
static StringList rest(StringList L){return handle.rest;}
static boolean isEmpty(StringList L){return handle == null;}
static StringList cons(String first, StringList rest){return new StringList(new StringCell(first, rest));}
StringList(StringCell handle){this.handle = handle;}
final static nil = new StringList(null); // note that nil != null}
class StringCell{String first;StringList rest;
StringCell(String first, StringList rest){this.first = first;this.rest = rest;}}
To add the toString method to this new List class:
public String toString(){StringBuffer b = new StringBuffer();b.append("(");StringList L = this;if( !isEmpty(L) ){b.append(first(L));L = rest(L);while( !isEmpty(L) ){b.append(" ");b.append(first(L));L = rest(L);}}b.append(")");return b.toString();}
Next Slide | Previous Slide | Contents |