In unserem Fall ist dies jeweils ein Verweis auf den Nachfolger, und am Ende der Liste steht stattdessen ein NIL-Wert. Die Liste als Ganzes wird angesprochen über einen Anker, also eine Variable, deren Inhalt ein Verweis auf das erste Listenelement ist, oder NIL bei einer leeren Liste.
Wir definieren daher:
Aus historischen Gründen erlaubt Modula 2 nicht beliebige Typen als Funktionsresultate, daher ersetzen wir einige Funktionen durch Prozeduren mit Ergebnisparametern:TYPE atom = ? (* irgend ein Typ *) liste = POINTER TO knoten; knoten = RECORD wert: atom; nach: liste END;
Diese Prozeduren sind extrem einfach; und hat man sich ihren Aufbau einmal eingeprägt, so wird man auf ihren weiteren Gebrauch verzichten und die betreffenden Anweisungen jeweils direkt hinschreiben.PROCEDURE newlist(VAR l: liste): BEGIN l := NIL; END newlist; PROCEDURE cons(a: atom; l: liste; VAR r: liste); (* r: = cons(a,l) *) BEGIN NEW(r); r^.wert := a; r^.nach := l; END cons; PROCEDURE isempty(l: liste): BOOLEAN; BEGIN RETURN l = NIL; END isempty; PROCEDURE head(l: liste; VAR a: atom); BEGIN a := l^.wert; END head; PROCEDURE tail(l: liste; VAR r: liste); BEGIN r := l^.nach; END tail;
Allerdings haben wir noch nicht berücksichtigt, daß head und tail partiell definiert sind und auf eine leere Liste nicht angewandt werden dürfen. Dies müssen wir noch korrigieren; und weil Modula 2, anders als Sprachen wie Ada und Java, keinen Standard-Fehlermechanismus anbietet, rufen wir hier eine Prozedur error auf, die noch geeignet zu definieren wäre. Eine Fortsetzung des Programmlaufs nach ihrem Aufruf macht natürlich wenig Sinn, da ja der Aufruf von head bzw. tail unzulässig war; es muß also ein logischer Fehler vorliegen, den man aufsuchen und beseitigen sollte.
Durch wiederholte Aufrufe von newlist und cons können wir nun Listen von beliebigem Inhalt aufbauen; für einige Standard-Anwendungen, die sich wieder als abstrakte Datentypen gut modellieren lassen, werden wir spezielle Mechanismen kennenlernen.PROCEDURE head(l: liste; VAR a: atom); BEGIN IF l = NIL THEN error("access to empty list") ELSE a := l^.wert END; END head; PROCEDURE tail(l: liste; VAR r: liste); BEGIN IF l = NIL THEN error("access to empty list") ELSE r := l^.nach END; END tail;