ADT Paar ISoder als Definitionsmodul geschrieben:
SORTS: Paar, CARDINAL
OPERATIONS:
Komb: CARDINAL CARDINAL Paar
Teil1: Paar CARDINAL
Teil2: Paar CARDINAL
RULES:
Teil1(Komb(x,y)) = x
Teil2(Komb(x,y)) = y
END Paar.
Damit können wir nun eine rein funktional-rekursive Lösung aufbauen:DEFINITION MODULE Paar; TYPE Paar; PROCEDURE Komb(x, y: CARDINAL): Paar; PROCEDURE Teil1(z: Paar): CARDINAL; PROCEDURE Teil2(z: Paar): CARDINAL; END Paar.
Damit hätten wir im Prinzip unser Problem gelöst, wenn wir den Typ Paar zur Verfügung hätten. Leider ist das aber nicht so; wir können ihn in Modula 2 nicht verwenden, ja nicht einmal realisieren: für einen opaken Typ belegen seine Werte zu viel Speicher, und er ist auch als Resultat einer Funktion nicht zulässig, weil Modula 2 dort aus historischen Gründen nur einfache Grundtypen erlaubt.PROCEDURE Fib(n: CARDINAL): CARDINAL; BEGIN RETURN Teil1(FPaar(n); END Fib; PROCEDURE FPaar(n: CARDINAL): Paar; BEGIN IF n <= 2 THEN RETURN Komb(1, 1) ELSE RETURN FKomb(FPaar(n-1)) END: END FPaar; PROCEDURE FKomb(x: Paar): Paar; BEGIN RETURN Komb(Teil1(x)+Teil2(x), Teil1(x)) END FKomb;
Wir müssen uns also irgendwie behelfen: entweder durch Übergang auf eine mächtigere Programmiersprache wie etwa Ada oder LISP; oder aber indem wir den Typ Paar auflösen und Hilfsvariablen sowie Ergebnisparameter verwenden.
Der Algorithmus und sein Verhalten ändert sich dabei nicht grundsätzlich: wir haben hier auch nichts anderes getan, als was eigentlich ein Compiler für uns erledigen sollte!PROCEDURE Fib(n: CARDINAL): CARDINAL; VAR x, y: CARDINAL; BEGIN FPaar(n, x, y); RETURN x; END Fib; PROCEDURE FPaar(n: CARDINAL; VAR x, y: CARDINAL); VAR u, v: CARDINAL; BEGIN IF n <= 2 THEN x := 1; y := 1; ELSE FPaar(n-1, u, v); x := u+v; y := u; END: END FPaar;
Wenn wir nun auf diese letzte Lösung wieder Dynamische Programmierung anwenden und die Teillösungen von unten nach oben einsammeln, so kommen wir im wesentlichen bei unserer früheren iterativen Lösung heraus. So hat sich der Kreis geschlossen.