All of the operations proposed for sequences have analogues for lists.
However, whereas many of the operations take sequences as inputs and yield
newly constructed sequences as outputs, the corresponding list operations
modify the contents of the list. For instance, the
insert-at-position operation on a list will change the list it is
given as input instead of creating an entirely new object to output. In
the Pascal implementation, this operation is a procedure (with a variable
parameter of type List) rather than a function.
Since the identity of a list is independent of its contents, a program may use several lists that all happen to be empty at the same time; so it is inappropriate to speak of ``the'' empty list. Instead of a constant, we have a function that creates and returns a new list, initially empty:
make-empty-list
Inputs: none.
Output: result, a list.
Preconditions: none.
Postcondition: The length of result is 0.
The analogue of construct-sequence changes an existing list instead of creating a new one:
prepend
Inputs: prefix, a value, and base, a list of
which the elements are of the same type as prefix.
Outputs: none.
Preconditions: none.
Postcondition: The length of base at output is one greater
than its length at input. The first element of base at output
is prefix. For every natural number k from one to the length of
base at input, the kth element of base at
input is the (k + 1)st element of base at output.
There is an operation to get the first element of a list, and another that undoes the effect of prepend:
first
Input: operand, a list.
Output: first, a value of the list's element type.
Preconditions: operand is not empty.
Postcondition: first is the first element of
operand.
delete-first
Input: operand, a list.
Outputs: none.
Preconditions: operand is not empty.
Postconditions: The length of operand at output is one less
than the length of operand at input. For every natural number
k from one to the length of operand at output, the
kth element of operand at output is the (k +
1)st element of operand at input.
To determine whether a given list is empty:
empty-list
Input: operand, a list.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if operand
is empty and false if it is not.
To compute the length of a list:
length
Input: operand, a list.
Output: result, a natural number.
Preconditions: none.
Postconditions: result is the number of positions in
operand.
Again, there are operations analogous to prepend, first, and delete-first, but taking place at the finish of the list:
append
Inputs: postfix, a value, and base, a list of
which the elements are of the same type as prefix.
Outputs: none.
Preconditions: none.
Postconditions: The length of base at output is one greater
than the length of base at input. The last element of
base at output is postfix. For every natural
number k from one to the length of base at input, the
kth element of base at output is the kth element
of base at input.
last
Input: operand, a list.
Output: last, a value of the list's element type.
Preconditions: operand is not empty.
Postcondition: last is the last element of
operand.
delete-last
Input: operand, a list.
Outputs: none.
Preconditions: operand is not empty.
Postconditions: The length of operand at output is one less
than the length of operand at input. For every natural number
k from one to the length of operand at output, the
kth element of operand at output is the kth
element of operand at input.
Sometimes even the user a list package wants to use a ``non-destructive'' version of some of these operations. The simplest approach is to provide a way to make an exact copy of a given list, in completely separate storage, and then to perform the ``destructive'' operation on the copy.
copy-list
Input: operand, a list.
Output: result, a list.
Preconditions: none.
Postconditions: operand is not the same list as
result. The length of operand is the length of
result. For every natural number k from one to the
length of operand, the kth element of
operand is the kth element of result.
Here are the analogues of the remaining sequence operations:
concatenate
Inputs: left-operand and right-operand, both
lists, with elements of the same type.
Outputs: none.
Preconditions: none.
Postconditions: The length of left-operand at output is the
sum of the lengths of left-operand at input and
right-operand. For every natural number k from one to
the length of left-operand at input, the kth element of
left-operand is the kth element of
left-operand at output. For every natural number k
from one to the length of right-operand, the kth
element of right-operand is the jth element of
left-operand at output, where j is the sum of k
and the length of left-operand at input.
recover-by-position
Inputs: position, a natural number, and ls, a
list.
Output: result, a value of the list's element type.
Precondition: position is greater that or equal to one and less
than or equal to the length of ls. (Note that this implies
that ls is not the empty list.)
Postcondition: result is the positionth element
of ls.
Since lists are mutable, one common operation is to store a new value at one particular position in the list:
assign-at-position
Inputs: position, a natural number; ls, a list;
and new-value, a value of the list's element type.
Outputs: none.
Precondition: position is greater that or equal to one and less
than or equal to the length of ls.
Postcondition: The length of ls at output is the length of
ls at input. For every natural number k from one to
the length of ls at output, the kth element of
ls at output is new-value if k is
position; otherwise, it is the kth element of
ls at input.
element-of
Inputs: candidate and ls, where ls
is a list and candidate is a value of its element type.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if candidate
is an element of ls and false if it is not.
To find the first position at which a particular value occurs in a particular list:
locate
Inputs: sought and ls, where ls
is a list and sought is a value of its element type.
Outputs: found, a Boolean, and position, a
natural number.
Preconditions: none.
Postconditions: Either sought is not an element of
ls and found is false, or
found is true and sought is the
positionth element of ls and, for every natural
number k from one to one less than position,
sought is not the kth element of ls.
sublist
Inputs: ls, a list, and start and
finish, both natural numbers.
Outputs: none.
Precondition: Both start and finish are greater
than or equal to one and less than or equal to the length of
ls at input.
Postconditions: The length of ls at output is 0 if
finish is less than start; otherwise, it is one
greater than the difference between finish and
start. For every natural number k from one to the
length of ls at output, the kth element of result is
the jth element of ls at input, where j is the
sum of start and k.
reverse
Input: operand, a list.
Outputs: none.
Preconditions: none.
Postcondition: The length of operand at output is the length
of operand at input. For every natural number k from
one to the length of operand at input, the kth element
of operand at input is the jth element of
operand at output, where j is the difference between
one more than the length of operand at input and k.
insert-at-position
Inputs: ls, a list; position, a natural
number; and elm, a value of the list's element type.
Outputs: none.
Precondition: position is greater than or equal to one and
less than or equal to one more than the length of ls.
Postconditions: The length of ls at output is one more than
the length of ls at input. elm is the
positionth element of ls at output. For every
natural number k from one to the length of ls at input,
the kth element of ls at input is the kth
element of ls at output if k is less than
position and the (k + 1)st element of ls
at output if k is greater than or equal to position.
delete-at-position
Inputs: ls, a list, and position, a natural
number.
Outputs: none.
Precondition: position is greater than or equal to one and
less than or equal to the length of ls at input.
Postconditions: The length of ls at output is one less than
the length of ls at input. For every natural number k
from one to the length of ls at output, the kth element
of ls at output is the kth element of ls
at input if k is less than position and the (k +
1)st element of ls at input if k is greater than or
equal to position.
delete-value
Inputs: ls, a list, and delend, a value of
the element type of ls.
Outputs: none.
Preconditions: none.
Postconditions: delend is not an element of ls at
output. For every integer k from one to the length of
ls at input, the kth element of ls at
input is either delend or the jth element of
ls at output, where j is the number of natural numbers
i such that i is greater than or equal to one, i is
less than or equal to k, and delend is not the
ith element of ls at input.
replace
Inputs: ls, a list, and displacer and
displaced, values of the element type of ls.
Outputs: none.
Preconditions: none.
Postconditions: The length of ls at output is the length of
ls at input. displaced is not an element of
ls at output. For every natural number k from one to
the length of ls at output, the kth element of
ls at output is displacer if the kth
element of ls at input is displaced; otherwise,
the kth element of ls at output is the kth
element of ls at input.
fill
Inputs: length, a natural number, and filler, a
value.
Output: result, a list of which the element type is the
type of filler.
Preconditions: none.
Postconditions: The length of result is length.
For every natural number k from one to length, the
kth element of result is filler.
The following meta-operations take operations as inputs as apply them either to create or to obtain values from lists.
generate-list
Inputs: generator, an operation that takes a positive integer
as its only input and yields one output, and length, a natural
number.
Output: result, a list of which the elements are of the
type of the output of generator.
Preconditions: none.
Postconditions: The length of result is length.
For every natural number k from one to length, the
kth element of result is the result of applying
generator to k.
transform-list
Inputs: ls, a list, and transformer, an operation
that takes one input, a value of the element type of ls, and
yields one output of the same type.
Outputs: none.
Preconditions: none.
Postconditions: The length of ls at output is the length of
ls at input. For every natural number k from one to
the length of ls at output, the kth element of
ls at output is the result of applying
transformer to the kth element of ls at
input.
apply-along-list
Inputs: ls, a list, and applicand, an
operation that takes one input, a value of the element type of
ls and yields no outputs.
Outputs: none.
Preconditions: none.
Postcondition: For every natural number k from one to the length of
ls, the operation applicand has been applied to
the kth element of ls. (If the same value occurs in
more than one position in ls, applicand is
applied to it as many times as it occurs.)
every-element
Inputs: ls, a list, and test, an operation
that takes one input, a value of the element type of ls, and
yields one output, a Boolean.
Output: result, a Boolean.
Preconditions: none.
Postconditions: result is false if there is an element
e of ls such that applying test to
e yields false. Otherwise, result is
true.
some-element
Inputs: ls, a list, and test, an operation
that takes one input, a value of the element type of ls, and
yields one output, a Boolean.
Output: result, a Boolean.
Preconditions: none.
Postconditions: result is true if there is an element
e of ls such that applying test to
e yields true. Otherwise, result is
false.
recover-by-test
Inputs: ls, a list, and test, an operation
that takes one input, a value of the element type of ls, and
yields one output, a Boolean.
Outputs: found, a Boolean, and sought, a value of
the element type of ls.
Preconditions: none.
Postconditions: Either (1) found is true and there is a
natural number k, such that sought is the kth
element of ls and applying test to
sought yields true, while, for any natural number
j greater than or equal to one and less than k, applying
test to the jth element of ls yields
false; or (2) found is false and, for any
natural number k greater than or equal to one and less than or equal
to the length of ls, applying test to the
kth element of ls yields false.
locate-by-test
Inputs: ls, a list, and test, an operation
that takes one input, a value of the element type of ls, and
yields one output, a Boolean.
Outputs: found, a Boolean, and position, a
natural number.
Preconditions: none.
Postconditions: Either (1) found is true and applying
test to the positionth element of
ls yields true, while, for any natural number k
greater than or equal to one and less than position, applying
test to the kth element of ls yields
false; or (2) found is false and, for any
natural number k greater than or equal to one and less than or equal
to the length of ls, applying test to the
kth element of ls yields false.
filter
Inputs: ls, a list, and test, an operation
that takes one input, a value of the element type of ls, and
yields one output, a Boolean.
Outputs: none.
Preconditions: none.
Postconditions: Applying test to any element of
ls at output yields true. For any natural number
k from one to the length of ls at output, there is a
natural number j such that the kth element of ls
at output is the jth element of ls at input and there
are exactly k natural numbers i greater than or equal to one
and less than or equal to j such that applying test to
the ith element of ls at input yields true.
Size field that indicates how many
components the list currently has. It's useful to save this theoretically
superfluous information, since many of the frequently invoked list
operations begin by checking the length of an argument list, and it's
inefficient to recompute this length every time by traversing the list and
tallying the components.
Here is the Lists module:
{ This module defines an interface for a list data type and implements it
for HP 9000 Series 700 workstations under HP-UX 9.x, using HP Pascal.
Programmer: John Stone, Grinnell College.
Original version: August 2-5, 1996.
}
$heap_dispose on$
module Lists;
$search 'elements.o'$
import Elements;
export
type
List = ^ListRecord; { an opaque type }
{ The MakeEmptyList function creates and returns a newly allocated,
empty list. }
function MakeEmptyList: List;
{ The PrependToList procedure takes a list and prepends an element to
it. }
procedure PrependToList (Prefix: Element; var Base: List);
{ The FirstOfList function returns the first element of a non-empty
list. }
function FirstOfList (Operand: List): Element;
{ The DeleteFirstOfList function takes a non-empty list and removes its
first element. }
procedure DeleteFirstOfList (var Operand: List);
{ The EmptyList function determines whether a given list is empty. }
function EmptyList (Operand: List): Boolean;
{ The LengthOfList function returns the length of a given list. }
function LengthOfList (Operand: List): Integer;
{ The AppendToList procedure takes a list and appends an element to it. }
procedure AppendToList (var Base: List; Postfix: Element);
{ The LastOfList function returns the last element of a non-empty list. }
function LastOfList (Operand: List): Element;
{ The DeleteLastOfList procedure takes a non-empty list and removes its
last element. }
procedure DeleteLastOfList (var Operand: List);
{ The CopyList function constructs and returns a copy of a given list,
in newly allocated storage. }
function CopyList (Operand: List): List;
{ The ConcatenateList procedure takes two lists and adds the elements
of the second operand at the end of the first operand. }
procedure ConcatenateList (var LeftOperand: List; RightOperand: List);
{ The RecoverByPositionFromList function returns the value occupying
a specified position in a list. }
function RecoverByPositionFromList (Position: Integer; Ls: List):
Element;
{ The AssignAtPositionInList procedure replaces the value occupying a
specified position in a list with a new value. }
procedure AssignAtPositionInList (Position: Integer; var Ls: List;
NewValue: Element);
{ The ElementOfList function determines whether a given value is an
element of a given list. }
function ElementOfList (Candidate: Element; Ls: List): Boolean;
{ The LocateInList procedure determines whether a given value is an
element of a given list and, if so, returns the least position at which
it occurs. }
procedure LocateInList (Sought: Element; Ls: List; var Found: Boolean;
var Position: Integer);
{ The Sublist function takes a list and prunes off all of it but a
section bounded by the positions indicated by Start and Finish. }
procedure Sublist (var Ls: List; Start, Finish: Integer);
{ The ReverseList procedure reverses the order of the elements in a given
list. }
procedure ReverseList (var Operand: List);
{ The InsertAtPositionInList procedure inserts an element at a specified
position in a list. }
procedure InsertAtPositionInList (var Ls: List; Position: Integer;
Elm: Element);
{ The DeleteAtPositionInList procedure removes the element at a specified
position in a list. }
procedure DeleteAtPositionInList (var Ls: List; Position: Integer);
{ The DeleteValueFromList procedure strips all occurrences of a specified
value out of a list. }
procedure DeleteValueFromList (var Ls: List; Delend: Element);
{ The ReplaceInList procedure replaces every occurrence of a specified
value in a list with a new value. }
procedure ReplaceInList (var Ls: List; Displacer, Displaced: Element);
{ The FillList function constructs and returns a list consisting
of a specified number of copies of a given element. }
function FillList (Length: Integer; Filler: Element): List;
{ The GenerateList function constructs a list of a specified
length by applying a given function to the positive integers in
ascending order until that length is reached. }
function GenerateList (function Generator (N: Integer): Element;
Length: Integer): List;
{ The TransformList procedure applies a transformation to every element
of a list. }
procedure TransformList (var Ls: List;
function Transformer (E: Element): Element);
{ The ApplyAlongList procedure applies a given procedure to each
successive element of a given list. }
procedure ApplyAlongList (Ls: List; procedure Applicand (E: Element));
{ The EveryElementOfList function determines whether every element
of a given list satisfies a given predicate. }
function EveryElementOfList (Ls: List;
function Test (E: Element): Boolean): Boolean;
{ The SomeElementOfList function determines whether at least one
element of a given list satisfies a given predicate. }
function SomeElementOfList (Ls: List;
function Test (E: Element): Boolean): Boolean;
{ The RecoverByTestFromList procedure determines whether any of the
elements of a given list satisfies a given predicate and, if so,
returns the one whose position is the least. }
procedure RecoverByTestFromList (Ls: List;
function Test (E: Element): Boolean; var Found: Boolean;
var Sought: Element);
{ The LocateByTestInList procedure determines whether any of the
elements of a given list satisfies a given predicate and, if so,
returns the least position occupied by such an element. }
procedure LocateByTestInList (Ls: List;
function Test (E: Element): Boolean; var Found: Boolean;
var Position: Integer);
{ The FilterList procedure strips out of a given list any elements that
do not satisfy a given predicate. }
procedure FilterList (var Ls: List; function Test (E: Element): Boolean);
{ The DeallocateList procedure recycles the storage associated with
a given list. }
procedure DeallocateList (var Operand: List);
implement
import StdErr;
const
FirstExceptionCode = 1;
UninitializedListException = 1;
FirstOfListException = 2;
DeleteFirstOfListException = 3;
LastOfListException = 4;
DeleteLastOfListException = 5;
RecoverByPositionFromListException = 6;
AssignAtPositionInListException = 7;
SublistException = 8;
InsertAtPositionInListException = 9;
DeleteAtPositionInListException = 10;
FillListException = 11;
GenerateListException = 12;
ExceptionException = 13;
LastExceptionCode = 13;
type
Link = ^ListComponent;
ListComponent = record
Datum: Element;
Next: Link
end;
ListRecord = record
Size: Integer;
Head: Link
end;
procedure ListExceptionHandler (ExceptionCode: Integer);
begin
if (ExceptionCode < FirstExceptionCode) or
(LastExceptionCode < ExceptionCode) then
ExceptionCode := ExceptionException;
WriteLn (StdErr, 'Exception #', ExceptionCode : 1,
' in module Lists:');
case ExceptionCode of
UninitializedListException:
WriteLn (StdErr, 'An operation was applied to an uninitialized ',
'list. ');
FirstOfListException:
WriteLn (StdErr, 'The empty list was passed to the ',
'FirstOfList function.');
DeleteFirstOfListException:
WriteLn (StdErr, 'The empty list was passed to the ',
'DeleteFirstOfList function.');
LastOfListException:
WriteLn (StdErr, 'The empty list was passed to the ',
'LastOfList function.');
DeleteLastOfListException:
WriteLn (StdErr, 'The empty list was passed to the ',
'DeleteLastOfList function.');
RecoverByPositionFromListException:
WriteLn (StdErr, 'An invalid index was passed to the ',
'RecoverByPositionFromList function.');
AssignAtPositionInListException:
WriteLn (StdErr, 'An invalid index was passed to the ',
'AssignAtPositionFromList function.');
SublistException:
WriteLn (StdErr, 'An invalid index was passed to the Sublist ',
'function.');
InsertAtPositionInListException:
WriteLn (StdErr, 'An invalid index was passed to the ',
'InsertAtPositionInList function.');
DeleteAtPositionInListException:
WriteLn (StdErr, 'An invalid index was passed to the ',
'DeleteAtPositionInList function.');
FillListException:
WriteLn (StdErr, 'A negative Length argument was passed to the ',
'FillList function.');
GenerateListException:
WriteLn (StdErr, 'A negative Length argument was passed to the ',
'GenerateList function.');
ExceptionException:
WriteLn (StdErr, 'The ListExceptionHandler procedure received ',
'an unknown exception code.')
end
end;
function CopyHelper (Hook: Link): Link;
var
OneMore: Link;
begin
if Hook = Nil then
CopyHelper := Nil
else begin
New (OneMore);
OneMore^.Datum := Hook^.Datum;
OneMore^.Next := CopyHelper (Hook^.Next);
CopyHelper := OneMore
end
end;
procedure DisposeRest (var Rest: Link);
begin
if Rest <> Nil then begin
DisposeRest (Rest^.Next);
Dispose (Rest)
end
end;
function MakeEmptyList: List;
var
Result: List;
begin
New (Result);
Result^.Size := 0;
Result^.Head := Nil;
MakeEmptyList := Result
end;
procedure PrependToList (Prefix: Element; var Base: List);
var
OneMore: Link;
begin
Assert (Base <> Nil, UninitializedListException,
ListExceptionHandler);
Base^.Size := Base^.Size + 1;
New (OneMore);
OneMore^.Datum := Prefix;
OneMore^.Next := Base^.Head;
Base^.Head := OneMore
end;
function FirstOfList (Operand: List): Element;
begin
Assert (Operand <> Nil, UninitializedListException,
ListExceptionHandler);
Assert (Operand^.Head <> Nil, FirstOfListException,
ListExceptionHandler);
FirstOfList := Operand^.Head^.Datum
end;
procedure DeleteFirstOfList (var Operand: List);
var
OneLess: Link;
begin
Assert (Operand <> Nil, UninitializedListException,
ListExceptionHandler);
Assert (Operand^.Head <> Nil, DeleteFirstOfListException,
ListExceptionHandler);
Operand^.Size := Operand^.Size - 1;
OneLess := Operand^.Head;
Operand^.Head := OneLess^.Next;
Dispose (OneLess)
end;
function EmptyList (Operand: List): Boolean;
begin
Assert (Operand <> Nil, UninitializedListException,
ListExceptionHandler);
EmptyList := (Operand^.Head = Nil)
end;
function LengthOfList (Operand: List): Integer;
begin
Assert (Operand <> Nil, UninitializedListException,
ListExceptionHandler);
LengthOfList := Operand^.Size
end;
procedure AppendToList (var Base: List; Postfix: Element);
var
OneMore: Link;
procedure AttachAtEnd (var Hook: Link);
begin
if Hook = Nil then
Hook := OneMore
else
AttachAtEnd (Hook^.Next)
end;
begin { procedure AppendToList }
Assert (Base <> Nil, UninitializedListException, ListExceptionHandler);
Base^.Size := Base^.Size + 1;
New (OneMore);
OneMore^.Datum := Postfix;
OneMore^.Next := Nil;
AttachAtEnd (Base^.Head)
end;
function LastOfList (Operand: List): Element;
function LastHelper (Hook: Link): Element;
begin
if Hook^.Next = Nil then
LastHelper := Hook^.Datum
else
LastHelper := LastHelper (Hook^.Next)
end;
begin { function LastOfList }
Assert (Operand <> Nil, UninitializedListException,
ListExceptionHandler);
Assert (Operand^.Head <> Nil, LastOfListException,
ListExceptionHandler);
LastOfList := LastHelper (Operand^.Head)
end;
procedure DeleteLastOfList (var Operand: List);
procedure DeleteHelper (var Hook: Link);
var
OneLess: Link;
begin
if Hook^.Next = Nil then begin
OneLess := Hook;
Hook := Nil;
Dispose (OneLess)
end
else
DeleteHelper (Hook^.Next)
end;
begin { procedure DeleteLastOfList }
Assert (Operand <> Nil, UninitializedListException,
ListExceptionHandler);
Assert (Operand^.Head <> Nil, DeleteLastOfListException,
ListExceptionHandler);
Operand^.Size := Operand^.Size - 1;
DeleteHelper (Operand^.Head)
end;
function CopyList (Operand: List): List;
var
Result: List;
begin { function CopyList }
Assert (Operand <> Nil, UninitializedListException,
ListExceptionHandler);
New (Result);
Result^.Size := Operand^.Size;
Result^.Head := CopyHelper (Operand^.Head);
CopyList := Result
end;
procedure ConcatenateList (var LeftOperand: List; RightOperand: List);
procedure ConcatenateHelper (var Hook: Link);
begin
if Hook = Nil then
Hook := CopyHelper (RightOperand^.Head)
else
ConcatenateHelper (Hook^.Next)
end;
begin { ConcatenateList }
Assert ((LeftOperand <> Nil) and (RightOperand <> Nil),
UninitializedListException, ListExceptionHandler);
LeftOperand^.Size := LeftOperand^.Size + RightOperand^.Size;
ConcatenateHelper (LeftOperand^.Head)
end;
function RecoverByPositionFromList (Position: Integer; Ls: List):
Element;
function RecoverHelper (Rest: Link; Current: Integer): Element;
begin
if Current = Position then
RecoverHelper := Rest^.Datum
else
RecoverHelper := RecoverHelper (Rest^.Next, Current + 1)
end;
begin { function RecoverByPositionFromList }
Assert (Ls <> Nil, UninitializedListException, ListExceptionHandler);
Assert ((1 <= Position) and (Position <= Ls^.Size),
RecoverByPositionFromListException,
ListExceptionHandler);
RecoverByPositionFromList := RecoverHelper (Ls^.Head, 1)
end;
procedure AssignAtPositionInList (Position: Integer; var Ls: List;
NewValue: Element);
procedure AssignHelper (Rest: Link; Current: Integer);
begin
if Current = Position then
Rest^.Datum := NewValue
else
AssignHelper (Rest^.Next, Current + 1)
end;
begin { AssignAtPositionInList }
Assert (Ls <> Nil, UninitializedListException, ListExceptionHandler);
Assert ((1 <= Position) and (Position <= Ls^.Size),
AssignAtPositionInListException,
ListExceptionHandler);
AssignHelper (Ls^.Head, 1)
end;
function ElementOfList (Candidate: Element; Ls: List): Boolean;
function ElementHelper (Rest: Link): Boolean;
begin
if Rest = Nil then
ElementHelper := False
else if EqualElement (Rest^.Datum, Candidate) then
ElementHelper := True
else
ElementHelper := ElementHelper (Rest^.Next)
end;
begin { function ElementOfList }
Assert (Ls <> Nil, UninitializedListException, ListExceptionHandler);
ElementOfList := ElementHelper (Ls^.Head)
end;
procedure LocateInList (Sought: Element; Ls: List; var Found: Boolean;
var Position: Integer);
procedure LocateHelper (Rest: Link; Current: Integer);
begin
if Rest = Nil then
Found := False
else if EqualElement (Rest^.Datum, Sought) then begin
Found := True;
Position := Current
end
else
LocateHelper (Rest^.Next, Current + 1)
end;
begin { procedure LocateInList }
Assert (Ls <> Nil, UninitializedListException, ListExceptionHandler);
LocateHelper (Ls^.Head, 1)
end;
procedure Sublist (var Ls: List; Start, Finish: Integer);
procedure SublistHelper (Rest: Link; Current: Integer);
begin
if Current < Start then begin
SublistHelper (Rest^.Next, Current + 1);
Dispose (Rest)
end
else begin
if Current = Start then
Ls^.Head := Rest;
if Current < Finish then
SublistHelper (Rest^.Next, Current + 1)
else begin
DisposeRest (Rest^.Next);
Rest^.Next := Nil;
Ls^.Size := Finish - Start + 1
end
end
end;
begin { function Sublist }
Assert (Ls <> Nil, UninitializedListException, ListExceptionHandler);
Assert ((1 <= Start) and (Start <= Ls^.Size) and
(1 <= Finish) and (Finish <= Ls^.Size), SublistException,
ListExceptionHandler);
if Finish < Start then begin
DisposeRest (Ls^.Head);
Ls^.Head := Nil;
Ls^.Size := 0
end
else
SublistHelper (Ls^.Head, 1)
end;
procedure ReverseList (var Operand: List);
var
BackLink: Link;
procedure ReverseHelper (Forwards: Link; var Backwards: Link);
var
Temporary: Element;
begin
if Forwards <> Nil then begin
Temporary := Forwards^.Datum;
ReverseHelper (Forwards^.Next, Backwards);
Backwards^.Datum := Temporary;
Backwards := Backwards^.Next
end
end;
begin { procedure ReverseList }
Assert (Operand <> Nil, UninitializedListException,
ListExceptionHandler);
BackLink := Operand^.Head;
ReverseHelper (BackLink, BackLink)
end;
procedure InsertAtPositionInList (var Ls: List; Position: Integer;
Elm: Element);
procedure InsertHelper (var Rest: Link; Current: Integer);
var
OneMore: Link;
begin
if Current = Position then begin
New (OneMore);
OneMore^.Datum := Elm;
OneMore^.Next := Rest;
Rest := OneMore
end
else
InsertHelper (Rest^.Next, Current + 1)
end;
begin { procedure InsertAtPositionInList }
Assert (Ls <> Nil, UninitializedListException, ListExceptionHandler);
Assert ((1 <= Position) and (Position <= Ls^.Size + 1),
InsertAtPositionInListException,
ListExceptionHandler);
InsertHelper (Ls^.Head, 1);
Ls^.Size := Ls^.Size + 1
end;
procedure DeleteAtPositionInList (var Ls: List; Position: Integer);
procedure DeleteHelper (var Rest: Link; Current: Integer);
var
OneLess: Link;
begin
if Current = Position then begin
OneLess := Rest;
Rest := Rest^.Next;
Dispose (OneLess)
end
else
DeleteHelper (Rest^.Next, Current + 1)
end;
begin { procedure DeleteAtPositionInList }
Assert (Ls <> Nil, UninitializedListException, ListExceptionHandler);
Assert ((1 <= Position) and (Position <= Ls^.Size),
DeleteAtPositionInListException,
ListExceptionHandler);
DeleteHelper (Ls^.Head, 1);
Ls^.Size := Ls^.Size - 1
end;
procedure DeleteValueFromList (var Ls: List; Delend: Element);
procedure DeleteHelper (var Rest: Link; var Tally: Integer);
var
OneLess: Link;
begin
if Rest <> Nil then begin
if EqualElement (Rest^.Datum, Delend) then begin
OneLess := Rest;
Rest := Rest^.Next;
Dispose (OneLess);
Tally := Tally - 1;
DeleteHelper (Rest, Tally)
end
else
DeleteHelper (Rest^.Next, Tally)
end
end;
begin { procedure DeleteValueFromList }
Assert (Ls <> Nil, UninitializedListException, ListExceptionHandler);
DeleteHelper (Ls^.Head, Ls^.Size)
end;
procedure ReplaceInList (var Ls: List; Displacer, Displaced: Element);
procedure ReplaceHelper (var Rest: Link);
begin
if Rest <> Nil then begin
if EqualElement (Rest^.Datum, Displaced) then
Rest^.Datum := Displacer;
ReplaceHelper (Rest^.Next)
end
end;
begin { procedure ReplaceInList }
Assert (Ls <> Nil, UninitializedListException, ListExceptionHandler);
ReplaceHelper (Ls^.Head)
end;
function FillList (Length: Integer; Filler: Element): List;
var
Filled: List;
function FillHelper (Remaining: Integer): Link;
var
Result: Link;
begin
if Remaining <= 0 then
FillHelper := Nil
else begin
New (Result);
Result^.Datum := Filler;
Result^.Next := FillHelper (Remaining - 1);
FillHelper := Result
end
end;
begin { function FillList }
Assert (0 <= Length, FillListException, ListExceptionHandler);
New (Filled);
Filled^.Size := Length;
Filled^.Head := FillHelper (Length);
FillList := Filled
end;
function GenerateList (function Generator (N: Integer): Element;
Length: Integer): List;
var
Generated: List;
function GenerateHelper (Current: Integer): Link;
var
Result: Link;
begin
if Length < Current then
GenerateHelper := Nil
else begin
New (Result);
Result^.Datum := Generator (Current);
Result^.Next := GenerateHelper (Current + 1);
GenerateHelper := Result
end
end;
begin { function GenerateList }
Assert (0 <= Length, GenerateListException, ListExceptionHandler);
New (Generated);
Generated^.Size := Length;
Generated^.Head := GenerateHelper (1);
GenerateList := Generated
end;
procedure TransformList (var Ls: List;
function Transformer (E: Element): Element);
procedure TransformHelper (Rest: Link);
begin
if Rest <> Nil then begin
Rest^.Datum := Transformer (Rest^.Datum);
TransformHelper (Rest^.Next)
end
end;
begin { procedure TransformList }
Assert (Ls <> Nil, UninitializedListException, ListExceptionHandler);
TransformHelper (Ls^.Head)
end;
procedure ApplyAlongList (Ls: List; procedure Applicand (E: Element));
procedure ApplyHelper (Rest: Link);
begin
if Rest <> Nil then begin
Applicand (Rest^.Datum);
ApplyHelper (Rest^.Next)
end
end;
begin { procedure ApplyAlongList }
Assert (Ls <> Nil, UninitializedListException, ListExceptionHandler);
ApplyHelper (Ls^.Head)
end;
function EveryElementOfList (Ls: List;
function Test (E: Element): Boolean): Boolean;
function EveryHelper (Rest: Link): Boolean;
begin
if Rest = Nil then
EveryHelper := True
else if Test (Rest^.Datum) then
EveryHelper := EveryHelper (Rest^.Next)
else
EveryHelper := False
end;
begin { function EveryElementOfList }
Assert (Ls <> Nil, UninitializedListException, ListExceptionHandler);
EveryElementOfList := EveryHelper (Ls^.Head)
end;
function SomeElementOfList (Ls: List;
function Test (E: Element): Boolean): Boolean;
function SomeHelper (Rest: Link): Boolean;
begin
if Rest = Nil then
SomeHelper := False
else if Test (Rest^.Datum) then
SomeHelper := True
else
SomeHelper := SomeHelper (Rest^.Next)
end;
begin { function SomeElementOfList }
Assert (Ls <> Nil, UninitializedListException, ListExceptionHandler);
SomeElementOfList := SomeHelper (Ls^.Head)
end;
procedure RecoverByTestFromList (Ls: List;
function Test (E: Element): Boolean; var Found: Boolean;
var Sought: Element);
procedure RecoverHelper (Rest: Link);
begin
if Rest = Nil then
Found := False
else if Test (Rest^.Datum) then begin
Found := True;
Sought := Rest^.Datum
end
else
RecoverHelper (Rest^.Next)
end;
begin { procedure RecoverByTestFromList }
Assert (Ls <> Nil, UninitializedListException, ListExceptionHandler);
RecoverHelper (Ls^.Head)
end;
procedure LocateByTestInList (Ls: List;
function Test (E: Element): Boolean; var Found: Boolean;
var Position: Integer);
procedure LocateHelper (Rest: Link; Current: Integer);
begin
if Rest = Nil then
Found := False
else if Test (Rest^.Datum) then begin
Found := True;
Position := Current
end
else
LocateHelper (Rest^.Next, Current + 1)
end;
begin { procedure LocateByTestInList }
Assert (Ls <> Nil, UninitializedListException, ListExceptionHandler);
LocateHelper (Ls^.Head, 1)
end;
procedure FilterList (var Ls: List; function Test (E: Element): Boolean);
procedure FilterHelper (var Rest: Link; var Tally: Integer);
var
OneLess: Link;
begin
if Rest <> Nil then begin
if Test (Rest^.Datum) then
FilterHelper (Rest^.Next, Tally)
else begin
OneLess := Rest;
Rest := Rest^.Next;
Dispose (OneLess);
Tally := Tally - 1;
FilterHelper (Rest, Tally)
end
end
end;
begin { procedure FilterList }
Assert (Ls <> Nil, UninitializedListException, ListExceptionHandler);
FilterHelper (Ls^.Head, Ls^.Size)
end;
procedure DeallocateList (var Operand: List);
begin
Assert (Operand <> Nil, UninitializedListException,
ListExceptionHandler);
DisposeRest (Operand^.Head);
Dispose (Operand)
end;
end.
This document is available on the World Wide Web as
http://www.math.grin.edu/~stone/courses/fundamentals/lists.html