Verschränkte Rekursion Typdefinition umfasst mehrere neue Typen und in den Typausdrücken können alle Typen auftreten. type `b wald = LeerW | Wald of `b * `b wald and à baum = LeerB| Baum of ‘a * (‘a baum) wald;; Der erste Teil dieser Typdefinition hat hierbei die Struktur einer Liste, der zweite führt zur Verschränkung durch Rückgriff auf „wald“. Durch verschränkt rekursive Sortendeklaration werden auch die darauf arbeitenden Funktionen rekursiv. Beispiel: Funktion zur Suche nach einem Teilbaum mit einer bestimten Wurzel x. let rec baumsuche(x,baum) = match baum with | LeerB LeerB | Baum(y,wald) when x = y Baum(y,wald) | Baum(y,wald) waldsuche(x,wald) and waldsuche (x,wald) = match wald with | LeerW LeerB | Wald (ersterB,restWald) let t = baumsuche (x,ersterBaum) in match t with | LeerB waldsuche (x,restWald) |_t ;; Weiteres Beispiel für Bäume mit mehreren „Kindbäumen“: (a,b)- Bäume. Ein (a,b)-Baum ist ein externer Suchbaum (d.h. alle Informationen befinden sich in den Blättern), für den gilt: - alle Blätter haben die selbe Tiefe - für die Anzahl N der Kinder eines jeden internen Knotens (außer der Wurzel) gilt: a < N < b - für die Wurzel gilt: 2 < N < b außerdem gilt für b: b 2a 1 Spezialfall: b = 2 a -1, hier spricht man von B-Bäumen. B-Bäume finden vor allem als Datenbank- Externspeicher Verwendung. Funktoren: Datentypen mit Funktionen als Argument. Bis hierher: Datentypen enthielten bisher Konstruktoren, deren Argumente wieder Datentypen sind. Bei den häufig verwendeten Sorten wie etwa stacks, Listen etc. sind die Zugriffsfunktionen immer dieselben und eng mit der Datenstruktur verbunden. Deshalb sinnvoll: Funktionen werden zum Bestandteil der Datenstruktur (ebenfalls zentrales Konzept oder OOP). type ’a listFum = Wert of ’a | Fum of (‘a ‘a) * ‘a listFum;; Der Konstruktor “Fum” enthällt hierbei aber als erstes Argument die Signatur ‘a ‘a und als zweites Argument ein Element des zu definiernden Datentyps. Soll ein Objekt dieses Datentyps erzeugt (für Klugscheißer: instanziert) werden, so müssen dem Konstruktor geeignete Eigenschaften übergeben werden, z.B.: let succ = (+) 1;; let div8= (/) 8;; let a = Fum(div8, Fum(succ, Wert 3));; Der Datentyp listFum ist also Listenstruktur, wobei der Kopf der Liste eine Funktion ist, die auf den Rest der Liste angewendet werden kann. Ausgeführt werden könnte eine solche Funktionsdeklaration mit Hilfe der Funktion: let rec compute = function | Wert v v | Fum (f,x) f(compute x);; hinmit ergäbe sich für compute a = 2. Beispiel 2: Graphen und Suche in Graphen. In einfacher Weise charakterisieren wir einen Graphen, indem wir jedem Knoten die Menge seiner direkten Nachfolger angeben. Graph besteht also aus einer Funktion, die zu jedem Knoten die Menge seiner Nachfolger berechnet bzw. zuordnet. type ’a graph = Graph of (’a ‘a list) Beispiel: Graph zur Darstellung der echten Teiler einer natürlichen Zahl. 12 13 8 14 9 6 4 7 5 2 3 1. Schritt: Definition der NachfolgerFunktion. let teiler n = let rec f m = match m with | m when (m<2) [] | m when ( n mod m = 0) & ( m <= n /2) m :: f (m-1) | m f (m-1) in f n;; 2. Schritt: Erzeugung des Objekts let graph1 = Graph(teiler);; Start Ziel In derart definierten Graphen soll nun nach Elementen gesucht werden, die gewisse Prädikate pred erfüllen. Vorgehen: 1.) Ausgehend vom Startknoten werden die direkten Nachfolgeknoten ermittelt. 2.) Bei Breitensuche werden zuerst alle Nachgfolger geprüft und dann erst die Nachfolger der Nachfolger; bei Teifensuche umgekehrt. 3.) Jeder Nachfolgerknoten verweist seinerseits auf eine Menge von Knoten, hierbei sollen nur die Knoten besucht (geprüft) werden, die vorher nicht bescuht wurden (Vermeidung von Zyklen) Algortihmus zur Teifensuche: type ’a reachable = OK of ’a | Fail;; type ‘a graph = Graph of (‘a ‘a List);; let getSuccFum(Graph(f))= f;; let depthsearch graph pred startnodes= let rec find visited startnodes = match startnodes with | [] Fail | a:: rest, when isElem (a,visited) find visited rest /*getrennt zu spezifizieren | a:: rest when (pred a) OK a | a:: rest find (a:: visited) ((( getSuccFum graph)a) @ rest) in find [] [startnodes];;