Informatik I - Institut für Informatik - Christian-Albrechts-Universität zu ...
Informatik I - Institut für Informatik - Christian-Albrechts-Universität zu ...
Informatik I - Institut für Informatik - Christian-Albrechts-Universität zu ...
Erfolgreiche ePaper selbst erstellen
Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.
Deklaration verwendet. Diese Rechenvorschrift isempty testet mittels einer verborgenen<br />
Hilfsrechenvorschrift ise, ob eine Menge leer ist. Auch die <strong>zu</strong>letzt deklarierte Rechenvorschrift<br />
elem verwendet eine Hilfsrechenvorschrift. Sie realisiert die Auswahl eines Knotens<br />
aus einer nichtleeren Menge, wie sie in (R5) <strong>für</strong> z vorausgesetzt wird, in deterministischer<br />
Weise. Es wird der kleinste in der Menge liegende Knoten abgeliefert.<br />
Im dritten Schritt haben wir nun Graphen <strong>zu</strong> implementieren. Wir stellen den vorausgesetzten<br />
Graphen g = (V, R) dar durch eine Funktion, die jedem Knoten die Menge seiner<br />
Nachfolger <strong>zu</strong>ordnet. Dies führt in ML <strong>zu</strong>r nachfolgenden Deklaration:<br />
type graph = node->nodeset;<br />
Damit wird im Prinzip jedem Knoten eine Nachfolgermenge <strong>zu</strong>geordnet. Natürlich sind wir<br />
bei dem speziellen Objekt g des Typs graph, das den vorausgesetzten Graphen g = (V, R)<br />
beschreibt, nur an den Werten von g bei Argumenten zwischen 1 und N interessiert.<br />
Aufbauend auf den Typ graph der Funktionen von den Knoten in die Knotenmengen<br />
erhalten wir auch eine äußerst einfache Realisierung der Nachfolgerfunktion succ wie folgt:<br />
fun succ (g : graph, x : node) : nodeset = g(x);<br />
Nach diesen Vorbereitungen können wir nun die obigen Rekursionen (R1) bis (R5) direkt<br />
nach ML übertragen. Wir erhalten die folgende Rechenvorschrift:<br />
fun reach (g : graph, x : node) : nodeset =<br />
let fun succs (s : nodeset) : nodeset =<br />
if isempty(s)<br />
then s<br />
else let val y : node = elem(s);<br />
in union(succ(g,y),succs(delete(s,y))) end;<br />
fun F (k : int) : nodeset =<br />
if k = 0 then insert(empty,x)<br />
else insert(succs(F(k-1)),x)<br />
in F(N-1) end;<br />
Im Vergleich <strong>zu</strong> den Funktionen reach, F und succs von oben sind in der Rechenvorschrift<br />
reach die Rechenvorschriften F und succs lokal deklariert. Durch diese Unterordnung ist<br />
es möglich, in F und succs jeweils mit einem Parameter aus<strong>zu</strong>kommen.<br />
Bei der oben angegebenen einfachen Implementierung von Mengen und Graphen durch<br />
Funktionstypen stellt sich natürlich das Problem, einen konkreten Graphen auf<strong>zu</strong>bauen<br />
und das Resultat einer Algorithmenanwendung <strong>zu</strong> visualisieren. Das erste Problem kann<br />
etwa gelöst werden durch die zwei nachfolgenden Rechenvorschriften:<br />
fun arcinsert (g : graph, x : node, y : node) : graph =<br />
fn (u : node) => if u = x then insert(succ(g,u),y)<br />
else succ(g,u);<br />
fun create (w : node list) : graph =<br />
if null(w) then fn (u : node) => empty<br />
else arcinsert(create(tl(tl(w))),hd(w),hd(tl(w)));<br />
152