// file: OpenList.java
// author: Robert M. Keller
// purpose: Implement Open Lists is java
import OpenListException;
/**
* OpenList is a type of uni-directional linked list that permits sharing
* of list tails. It is similar to the list representation used in many
* functional languages, such as rex, Lisp, etc.
*/
class OpenList
{
/**
the default left paren used when a list is printed.
Defaults are used when the toString() method is called, i.e. whenever
an OpenList is automatically cast to a String, as in printing.
To use different punctuation, or no punctuation, use the three-argument
toString, and supply the punctuation you want.
*/
public static String defaultLeftParen = "[";
/** the default right paren used when a list is printed */
public static String defaultRightParen = "]";
/** the default space used when a list is printed */
public static String defaultSpacer = ", ";
/**
* the one and only empty OpenList. Do not create any others.
* This list is represented by a unique cell allocated for the purpose.
* The first and rest are not intended to be used. We do not use null
* for this list, so that we can call methods on it.
*/
final public static OpenList nil = cons(null, null);
/** exception message for first of empty list */
public static String firstOfOpenListException = "first() of empty list";
/** exception message for rest of empty list */
public static String restOfOpenListException = "rest() of empty list";
/** the Object in the first cell of a non-empty list */
private Object First;
/** the rest of a list, defined to be an OpenList of all but the first cell */
private OpenList Rest;
/**
* Construct an OpenList from its first and rest.
* This constructor is private because it is intended that the
* pseudo-constructor (or "factor") cons be used outside.
*
* @param _First the first Object in the list
* @param _Rest list of the rest of the objects in the list
*/
private OpenList(Object _First, OpenList _Rest)
{
First = _First;
Rest = _Rest;
}
/**
* Return a new OpenList constructed from its first and rest.
*
* @param _First the first Object in the list
* @param _Rest list of the rest of the objects in the list
* @return new OpenList from first and rest
*/
public static OpenList cons(Object _First, OpenList _Rest)
{
return new OpenList(_First, _Rest);
}
/**
* Return the first of this non-empty OpenList.
*
* @return first of this list
* @exception OpenListException if this list happens to be empty
*/
public Object first() throws OpenListException
{
if( isEmpty() )
{
throw new OpenListException(firstOfOpenListException);
}
return First;
}
/**
* Return the first of the argument, a non-empty OpenList.
*
* @param List the list the rest of which is to be returned
* @return first of the argument list
* @exception OpenListException if the argument happens to be empty
*/
public static Object first(OpenList List) throws OpenListException
{
return List.first();
}
/**
* Return the rest, i.e. all a list of all but the first of this non-empty
* OpenList.
*
* @return rest of this list
* @exception OpenListException if this list happens to be empty
* will be thrown.
*/
public OpenList rest() throws OpenListException
{
if( isEmpty() )
{
throw new OpenListException(restOfOpenListException);
}
return Rest;
}
/**
* Return the rest, i.e. all a list of all but the first of the argument
* non-empty OpenList.
*
* @parameter List the list the rest of which is to be returned
* @return rest of the argument list
* @exception OpenListException if the argument happens to be empty
*/
public static OpenList rest(OpenList List) throws OpenListException
{
return List.rest();
}
/**
* Return true if this list is empty, false otherwise.
* Note: Done by comparing this list to nil, which should be the only
* way to determine whether the list is empty.
* @return true if this list is empty, false otherwise
*/
public boolean isEmpty()
{
return this == nil;
}
/**
* Return true if this list is non-empty, false otherwise.
* @return true if this list is non-empty, false otherwise
*/
public boolean nonEmpty()
{
return this != nil;
}
/**
* Return true if the argument list is empty, false otherwise.
* Note: Done by comparing this list to nil, which should be the only
* way to determine whether the list is empty.
*
* @param List the OpenList for which emptiness is to be determined
* @return true if the argument list is empty, false otherwise
*/
public static boolean isEmpty(OpenList List)
{
return List.isEmpty();
}
/**
* Return true if the argument list is non-empty, false otherwise.
*
* @param List the OpenList for which non-emptiness is to be determined
* @return true if the argument list is non-empty, false otherwise
*/
public static boolean nonEmpty(OpenList List)
{
return List.nonEmpty();
}
/**
* Create a new list formed by elements of the first argument followed by
* those of the second.
*
* @param L1 the list providing the initial elements of the result
* @param L2 the list providing the final elements of the result
* @return the list containing the elements of the first list followed
* by those of the second
*/
public static OpenList append(OpenList L1, OpenList L2)
{
if( L1.isEmpty() )
{
return L2;
}
else
{
return cons(L1.first(), append(L1.rest(), L2));
}
}
/**
* Return a new list containing the elements of the argument list in
* reverse order.
*
* @param L1 the list providing the elements
* @return the reverse of the argument list.
*/
public static OpenList reverse(OpenList L1)
{
OpenList result = nil;
for( ; L1.nonEmpty(); L1 = L1.rest() )
{
result = cons(L1.first(), result);
}
return result;
}
/**
* Return the number of elements of this list.
* @return the number of elements of this list
*/
public int length()
{
OpenList L = this;
int result = 0;
for( ; L.nonEmpty(); L = L.rest() )
{
result++;
}
return result;
}
/**
* Return the nth element of this list, starting with n = 0, 1, 2, ...
* If there is no nth element, throws an EmptyList exception so indicating.
*
* @param n the index (0, 1, 2, ...) of the desired element.
* @return the nth element of this list.
* @exception OpenListException if there is no nth element
*/
public Object nth(int n) throws OpenListException
{
int remaining = n;
OpenList L = this;
try
{
while( remaining > 0 )
{
L = L.rest();
remaining--;
}
return L.first();
}
catch( OpenListException e )
{
throw new OpenListException("nth of an OpenList of length " + length()
+ ", where n == " + n);
}
}
/**
* Returns the first n elements of an OpenList. If there aren't n
* elements in the list, returns the entire list. If n <= 0, returns nil.
*
* @param n the length of the desired prefix of this list.
* return the prefix of this list of the desired length, or the entire
* list itself if the list is not as long as desired.
*/
public OpenList prefix(int n)
{
if( isEmpty() || n <= 0 )
{
return nil;
}
return cons(first(), rest().prefix(n-1));
}
/**
* Convert this OpenList to a String, using default punctuation.
*
* @return String representing OpenList
*/
public String toString()
{
return toString(defaultLeftParen, defaultSpacer, defaultRightParen);
}
/**
* Convert this OpenList to a String, using the arguments as punctuation.
*
* @param leftParen String that is output before the list elements
* @param spacer String that is output between list elements
* @param rightParen String that is output after the list elements
* @return String representing OpenList
*/
public String toString(String leftParen,
String spacer,
String rightParen)
{
StringBuffer buffer = new StringBuffer();
buffer.append(leftParen);
if( nonEmpty() )
{
buffer.append(first().toString());
OpenList remainder = rest();
while( remainder.nonEmpty() )
{
buffer.append(spacer);
buffer.append(remainder.first());
remainder = remainder.rest();
}
}
buffer.append(rightParen);
return buffer.toString();
}
/**
* test program:
* exercises a variety of the defined methods, printing out results
*/
public static void main(String arg[])
{
try
{
OpenList L0 = nil;
System.out.println("L0 = " + L0);
OpenList L1 = cons("a", cons("b", cons("c", nil)));
System.out.println("L1 = " + L1);
OpenList L2 = cons(cons("b", cons("c", nil)), cons("d", nil));
System.out.println("L2 = " + L2);
OpenList L3 = cons(L1, cons(L2, nil));
System.out.println("L3 = " + L3);
OpenList L4 = cons(L1, L2);
System.out.println("L4 = " + L4);
OpenList L5 = cons(L2, L1);
System.out.println("L5 = " + L5);
OpenList L6 = cons(new Integer(1), nil);
System.out.println("L6 = " + L6);
OpenList L7 = cons(new Integer(1),
cons(new Integer(2),
cons(new Integer(3),
cons(new Integer(4),
nil))));
System.out.println("L7 = " + L7);
System.out.println("append(L1, L2) = " + append(L1, L2));
System.out.println("reverse(L5) = " + reverse(L5));
System.out.println("append(reverse(L7), reverse(L1)) = "
+ append(reverse(L7), reverse(L1)));
System.out.println("reverse(append(L1, L7)) = "
+ reverse(append(L1, L7)));
System.out.println("L5.length() = " + L5.length());
System.out.println("L5.nth(2) = " + L5.nth(2));
System.out.println("L5.prefix(3) = " + L5.prefix(3));
System.out.println("L5.nth(4) = " + L5.nth(4));
}
catch( Exception e )
{
System.err.println("*** caught: " + e);
}
}
}