Funktionale Programmierung ALP I µ-Rekursive Funktionen WS 2012/2013 Prof. Dr. Margarita Esponda Prof. Dr. Margarita Esponda Funktionale Programmierung Primitiv-rekursive Funktionen Jede primitiv-rekursive Funktion ist Loop-berechenbar. Das bedeutet, dass jede PR-Funktion in der Loop-Programmiersprache formuliert werden kann. Jede Loop-berechenbare Funktion ist auch eine PR-Funktion. Loop-Sprache: - stark beschränkte Programmiersprache nur Addition, Zuweisungen und loop-Schleifen sind erlaubt - Loop-Programme terminieren immer. - Die Laufzeit kann genau berechnet werden. Prof. Dr. Margarita Esponda Funktionale Programmierung Loop-Sprache Syntaktische Komponenten: 3 Schlüsselwörter: Loop, Do, End 4 Sondersymbole: +, -, ;, := Beliebige Variablennamen: x1 , x2 , x3 , . . . Beliebige Konstanten: 0, 1, 2, . . . Syntax in BNF: P := xi := x j + c | xi := x j − c | P; P | LOOP xi DO P END Prof. Dr. Margarita Esponda Wertzuweisungen sequentielle Komposition endliche Schleife Funktionale Programmierung Primitiv-rekursive Funktionen Zusammengefast: Jede primitiv-rekursive Funktion kann mit Hilfe einer Loop-Schleife berechnet werden und umgekehrt. Addition x1 + x2 → x3 x3 := x1 + 0 LOOP x2 DO x3 := x3 + 1 END Prof. Dr. Margarita Esponda Berechnet die n-te Fibonacci-Zahl (Eingabe in xn und Ausgabe in xfib) x2 := 0; x1 := x2 +1; xfib := 0; xn := n; LOOP xn DO x2 := xfib + 0 LOOP x1 xfib := xfib + 1 END x1 := x2 + 0 END Funktionale Programmierung Ackermann-Funktion Bis 1926 vermutete Hilbert, dass jede totale berechenbare Funktion primitiv rekursiv ist, bis zwei von seinen Schülern, Ackermann (1928) und Sudan (1927), Funktionen entdeckten, die nicht primitiv rekursiv aber total berechenbar sind. Ackerman-Péter-Funktion ack :: Integer -> Integer -> Integer ack 0 n = n+1 ack (m+1) 0 = ack m 1 ack (m+1) (n+1) = ack m (ack (m+1) n) Prof. Dr. Margarita Esponda Ackerman-Péter-Funktion ack 0 ack (m+1) Reduktionsverlauf: ack 2 3 => => m+1 n+1 => => => => => => => => => => => => => => => => => => => => ack 1 ack 1 ack 1 ack 1 ack 1 ack 1 ack 1 ack 1 ack 1 ack 1 ack 1 ack 1 ack 1 ack 1 ack 1 ack 1 ack 1 ack 1 ack 1 ack 1 ack 1 ... (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 2) (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack 5) (ack (ack (ack (ack (ack n =n+1 0 = ack m 1 ack (m+1) (n+1) 2 1 1 1 1 1 1 0 0 0 0 0 0 0 1)) (ack (ack (ack (ack (ack 3)) (ack (ack (ack (ack (ack (ack 4)) 1 0 0 0 0 4)) (ack (ack (ack (ack = ack m (ack (m+1) n) (m+1) rekursive Aufrufe von (n-1) 4 rekursive Aufrufe von 1 2 1 0 0 0 0))) 1))) (ack 1 0)))) (ack 0 1)))) 2))) 1 0 0 0 0 0 2))) (ack (ack (ack (ack 3))) 1 0 0 0 3))) (ack 1 2)))) (ack 0 (ack 1 1))))) (ack 0 (ack 0 (ack 1 0)))))) 1 0 0 0 1)))) (ack 1 0))))) (ack 0 1))))) 2)))) ... => ack => ack => ack => ack => ack => ack => ack => ack => ack => ack => ack => ack => ack => ack => ack => ack => ack => ack => ack => ack => ack => ack => ack => 9 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 (ack (ack (ack (ack (ack (ack (ack 7 (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack 8 0 0 0 0 0 0 0 (ack (ack (ack (ack (ack (ack 6) 0 0 0 0 0 0 (ack (ack (ack (ack (ack 5)) 0 0 0 0 0 (ack (ack (ack (ack 4))) 0 0 0 0 (ack 0 (ack 1 0)))))) (ack 0 (ack 0 1)))))) (ack 0 2))))) 3)))) ack 0 ack (m+1) 1 0 0 0 0 0 0 0 0 0 0 0 0 0 6) (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack 7)) 1 0 0 0 0 0 0 0 0 0 0 0 5)) (ack (ack (ack (ack (ack (ack (ack (ack (ack (ack 6)) n =n+1 0 = ack m 1 ack (m+1) (n+1) 1 0 0 0 0 0 0 0 0 0 4))) (ack (ack (ack (ack (ack (ack (ack (ack 5))) = ack m (ack (m+1) n) 1 3)))) 0 (ack 1 2))))) 0 (ack 0 (ack 1 1)))))) 0 (ack 0 (ack 0 (ack 1 0))))))) 0 (ack 0 (ack 0 (ack 0 1))))))) 0 (ack 0 (ack 0 2)))))) 0 (ack 0 3))))) 0 4)))) Die Argumente bewegen sich nicht immer in Richtung der Abbruchbedingung. Funktionale Programmierung Ackermann-Funktion . . . ack 4 2 => Prof. Dr. Margarita Esponda (19,729 Ziffern) Idee die Folge n+1, n+m, n*m, nm, . . . ... ab hier reichen unsere bekannten arithmetischen Operationen nicht mehr Up-Arrow-Notation von Knuth a b=a x a x … x a b Wiederholungen von a a b =a a … a b Wiederholungen von a =a (a … (a a a a) …) = a .a . . b Wiederholungen von a a b=a a … b Wiederholungen von a a Up-Arrow-Notation von Knuth m Wiederholungen von im allgemeinen: a m b =a … b = a m-1a m-1… m-1 a b Wiederholungen von a = a m-1(a m-1 … (a m-1 a)…) Beispiel: 2 3 2 2 3 3 =2x2x2 =8 =2 2 2 =2x2x2x2 =2 = 16 = 2 2 =2 2 4 = 65536 2 4 = 2 4 = 2 16 Funktionale Programmierung Ack(m,n) ack(0,n) = n+1 ack(1,n) = n+2 =2+ (n+3) -3 ack(2,n) = 2n+3 =2x (n+3) -3 ack(3,n) = 2(n+3) -3 = 2 "" (n+3) -3 ack(4,n) = = 2 (n+3) -3 ack(5,n) = = 2 (n+3) -3 = 2 m-2 (n+3) -3 … ack(m,n) = Prof. Dr. Margarita Esponda Funktionale Programmierung Ackermann-Funktion - verschachtelte Rekursion. Das bedeutet, ein Argument des rekursiven Aufrufs muss selbst erst rekursiv berechnet werden - nicht primitiv rekursiv, aber berechenbar - wächst schneller als jede primitiv-rekursive Funktion - eine Komplexitätsanalyse wird unmöglich - der Verwaltungsaufwand des Ausführungsstapels ist extrem groß Prof. Dr. Margarita Esponda Funktionale Programmierung Sudan-Funktion Definition: in Haskell: sud sud sud sud :: Integer -> Integer -> Integer -> Integer 0xy = x+y nx0 =x n x y = sud (n-1) (sud n x (y-1)) ((sud n x (y-1)) + (y-1) + 1) prelude> sud 2 2 2 15569256417 it :: Integer (3501.87 secs, 302851025060 bytes) Prof. Dr. Margarita Esponda Funktionale Programmierung µ-Rekursive Funktionen 1. Alle primitiv-rekursive Funktionen sind auch µ-Rekursive Funktionen. 2. mit dem µ-Operator als weiterem Konstruktionsoperator wird die Klasse der primitiv-rekursiven Funktionen auf die Klasse der partiellen µ-rekursiven Funktionen erweitert 3. und damit die Klasse der intuitiv berechenbaren Funktionen konstruiert. Prof. Dr. Margarita Esponda Funktionale Programmierung Der unbeschränkte µ-Operator Sei f : N m+1 →N eine partielle Funktion, dann ist die partielle Funktion µf : Nm→N definiert durch: µf (x1, . . . ,xm) = min M (f, x1, . . . ,xm ) falls M(f, x1, . . . ,xm) ≠ θ undefiniert sonst wobei die Menge M ( f, x1, . . . , xm) als { n≥0 | f (x1, . . . ,xm, n ) = 0 und f (x1, . . . ,xm , k ) für alle n≥k definiert ist } Prof. Dr. Margarita Esponda Funktionale Programmierung Der unbeschränkte µ-Operator Sei b eine Funktion, die angewendet auf x, y (natürliche Zahlen) testet, ob y eine Primzahl und gleichzeitig größer als x ist. b (x, y) = 1 falls y eine Primzahl größer als x ist 0 sonst Folgende Funktion liefert die kleinste Primzahl, die größer als x ist: f(x) = µy [ 1 - b(x, y) ] liefert das kleinste y, sodass die Bedingung erfüllt wird. Sei g (n, y) = 1 - b(n, y) Prof. Dr. Margarita Esponda y := 0; while g(n,y) ≠ 0 do y := y+1; f := y; Funktionale Programmierung Äquivalenz vieler Berechnungsmodelle Effektiv Berechenbare Funktionen Mathematische Modelle Maschinelle Modelle Register Maschinen ALP II Prof. Dr. Margarita Esponda Turing-Maschine λ-Kalkül Kombinatorische Logik µ-rekursive Theoretische Informatik I Funktionen Allgemein rekursive Funktionen Funktionale Programmierung µ-Rekursive Funktionen Mathematische Modelle µ-rekursive Effektiv Berechenbare Funktionen Primitiv Rekursive Funktionen LoopBerechenbar Funktionen Allgemein rekursive Funktionen WhileBerechenbar Maschinelle Modelle Prof. Dr. Margarita Esponda