Programming Language for Old Timers


by David A. Moon
February 2006 .. September 2008

Comments and criticisms to dave underscore moon atsign alum dot mit dot edu.


Previous page   Table of Contents   Next page


Collection Protocol

Collection is a subprotocol of sequence that is implemented by any object that acts as a collection of other objects. If start-iteration is called twice on a collection, and the collection is not modified, each iteration will traverse the same elements in the same order. If the collection is modified in any way, the order of elements can be completely changed.

A sequence that is not a collection might be something like an I/O device that does not return the same elements each time it is iterated.

The following method requirements, in addition to the sequence functions, constitute the collection protocol:

defprotocol collection is sequence
  =(x is collection, y is collection)
  length(x is collection) is integer
  empty?(x is collection) is boolean
  member?(element, x is collection) is boolean
  add(element, x is collection) is collection
  adjoin(element, x is collection) is boolean           ; true if new element
  remove(element, x is collection) is boolean           ; true if was present
  mimic(x is collection) is collection
  any?(function is function, x is collection, rest: more is collection) is boolean
  every?(function is function, x is collection, rest: more is collection) is boolean
  map(function is function, x is collection, rest: more is collection)
  reduce(function is function, initial-value, x is collection, rest: more is collection)
  reduce-right(function is function, initial-value, x is collection, rest: more is collection)
  reverse(x is collection) is collection

= works on all objects, but it is specifically defined to compare collections element-by-element.

add returns a collection which is like the argument collection but also contains the new element. add might or might not side-effect the argument collection.

adjoin modifies the argument collection so it also contains element, unless it already contains element.

The mimic function returns a collection of the same type and length as its argument but not necessarily the same contents. Mimic also works on functions, returning a new function that initially has the same methods. Modifications to the method collection of the mimic do not affect the original function, and vice versa.

The functions any?, every?, map, reduce, and reduce-right iterate over all their collection arguments in lock step, stopping as soon as any collection is exhausted. At each step they invoke their function argument on the current elements of each collection.

any? stops as soon as the function returns a value other than false, and returns that value. any? returns false when a collection is exhausted.

every? stops and returns false as soon as the function returns false. every? returns true when a collection is exhausted.

map creates and returns a collection of the same type as its x argument, using the mimic function or its equivalent. Each element of the collection is the result returned by the function when invoked on the corresponding elements of the argument collections.

reduce invokes the function on the current collection elements and the current value and sets the current value to the result of the function. The current value is initialized to the initial-value argument. reduce returns the current value when a collection is exhausted.

reduce-right is the same as reduce except it iterates backwards over the collections.

Note that for optimization you can define methods for any?, every?, map, reduce, and/or reduce-right that accept a specific number of collection arguments in addition to the general methods that accept one or more collections. For example,

defun map(f is function, x is list) ...
defun map(f is function, x is list, y is list) ...

Many collections implement assignable-sequence in addition to sequence.


Previous page   Table of Contents   Next page