Funktionales Programmieren Programmierparadigmen Einführung in Scheme D. Rösner Institut für Wissens- und Sprachverarbeitung Fakultät für Informatik Otto-von-Guericke Universität Magdeburg c Sommer 2009, 31. März 2009, 2009 D.Rösner D. Rösner PGP 2009 . . . 1 Funktionales Programmieren Gliederung 1 Funktionales Programmieren Scheme Einführung Scheme vs. Haskell Programm-Daten-Äquivalenz Funktionen höherer Ordnung Skopus Beispiel: Newton-Verfahren D. Rösner PGP 2009 . . . 2 Funktionales Programmieren Scheme Scheme als funktionale Sprache: Diskussion von Scheme im Vergleich mit Haskell m.a.W. Gemeinsamkeiten und Unterschiede Haskell als ‘Blaupause’ für funktionale Sprachen Grundlegendes: Interpreter Definition von Werten mit define (define <name> <wert>) D. Rösner PGP 2009 . . . 4 Funktionales Programmieren Scheme Scheme als funktionale Sprache: Funktionen sind Objekte erster Ordnung eine Interaktion: 1 ]=> (define pi 3.1415) ;Value: pi 1 ]=> pi ;Value: 3.1415 1 ]=> (define quadriere (lambda (zahl) (* zahl zahl))) ;Value: quadriere 1 ]=> (quadriere pi) ;Value: 9.86902225 D. Rösner PGP 2009 . . . 5 Funktionales Programmieren Scheme Scheme: Anonyme Funktionen Syntax: (lambda <parameterliste> <koerper>) überall dort verwendbar, wo auch mit Symbol auf Funktion verwiesen werden kann 1 ]=> ((lambda (n) (* n n)) 3) ;Value: 9 D. Rösner PGP 2009 . . . 6 Funktionales Programmieren Scheme Scheme: Anonyme Funktionen alternative Syntax für benannte Funktionen (define (<name> <par-1> ... <par-n>) <koerper>) statt (define <name> (lambda (<par-1> ... <par-n>) <koerper>)) D. Rösner PGP 2009 . . . 7 Funktionales Programmieren Scheme Scheme: Übersicht vordefinierte Datentypen Zahlen: ganze, rationale, Fliesskomma, ... Strings Zeichen boolesche Werte: #t, #f wichtigster aggregierter Datentyp: Liste Konstruktor: cons Selektoren: car, cdr Prädikate: null? wichtige Kontrollstrukturen: if cond Funktionen zur Konversion zwischen verschiedenen Typen D. Rösner PGP 2009 . . . 8 Funktionales Programmieren Scheme Scheme vs. Haskell Syntax: in Scheme: Klammerung innerhalb geschachtelter Ausdrücke in Haskell: Vorrangregeln, Layoutregel Typisierung? in Scheme: keine Typisierung; in Haskell: strenge Typisierung Striktheit? Scheme: strikt Haskell: non-strikt D. Rösner PGP 2009 . . . 9 Funktionales Programmieren Scheme Striktheit vs. Non-Striktheit Eine (seiteneffekt-freie) Funktion heisst strikt, wenn gefordert wird, dass alle ihre Argumente definiert sind und so die Evaluationsordnung das Ergebnis nicht verändert. Eine Funktion heisst non-strikt, wenn für sie die Forderung nach Striktheit nicht erhoben wird. Eine Sprache heisst strikt, wenn gefordert wird, dass alle ihre Funktionen strikt. Eine Sprache heisst non-strikt, wenn sie die Definition non-strikter Funktionen zulässt. D. Rösner PGP 2009 . . . 10 Funktionales Programmieren Scheme Scheme vs. Haskell Art der Auswertung? in Haskell: verzögerte Auswertung (lazy evaluation) für alle Argumente in Scheme: Auswertung für alle Argumente; aber: verzögerte Auswertung und call-by-need möglich mit delay und force in Scheme nicht vordefiniert vorhanden sind u.a. Listenkomprehension und Fallunterscheidung durch Pattern Matching D. Rösner PGP 2009 . . . 11 Funktionales Programmieren Scheme Scheme: Programm-Daten-Äquivalenz Programme haben die Form von Listen Scheme (und Lisp) sind homoikonisch, d.h. selbstrepräsentierend Programme können mit allen Listenfunktionen bearbeitet werden Beispiel: (define compose (lambda (f g) (lambda (x) (f (g x))))) 1 ]=> ((compose car cdr) ’(1 2 3)) ;Value: 2 D. Rösner PGP 2009 . . . 12 Funktionales Programmieren Scheme Scheme: Programm-Daten-Äquivalenz Beispiel cont.: (define compose2 (lambda (f g) (eval (list ’lambda ’(x) (list f (list g ’x))) (scheme-report-environment 5)))) 1 ]=> ((compose2 car cdr) ’(1 2 3)) ;Value: 2 } D. Rösner PGP 2009 . . . 13 Funktionales Programmieren Scheme Scheme: weitere Aspekte Funktionen mit beliebiger Anzahl von Argumenten möglich (sog. Restparameter, der an Liste gebunden) Beispiel: (define (avg . nums) (average nums)) average erwartet Liste als Argument Definition: (define (average nums) (/ (apply + nums) (length nums))) D. Rösner PGP 2009 . . . 14 Funktionales Programmieren Scheme Scheme: Funktionen höherer Ordnung z.B. Falten einer zweistelligen Funktion in eine Liste: (define fold (lambda (f l i) (if (null? l) i ;; identity for f (f (car l) (fold f (cdr l) i))))) D. Rösner PGP 2009 . . . 15 Funktionales Programmieren Scheme Scheme: Funktionen höherer Ordnung partielle Anwendungen sind bei Funktionen im Curry-Format möglich (define curry (lambda (f) (lambda (a) (lambda (b) (f a b))))) 1 ]=> (((curry +) 3) 4) ;Value: 7 (define curried-plus (curry +)) D. Rösner PGP 2009 . . . 16 Funktionales Programmieren Scheme Scheme vs. Haskell: Sichtbarkeit von Definitionen die Definitionen auf dem Toplevel von Scheme sind ‘global’ sichtbar wechselseitige Bezugnahme in rekursiven Definitionen ist möglich Beispiel: 1 ]=> (define (isOdd n) (if (<= n 0) () (isEven (- n 1)))) ;Value: isodd ... D. Rösner PGP 2009 . . . 17 Funktionales Programmieren Scheme Scheme vs. Haskell: Sichtbarkeit von Definitionen Beispiel cont.: 1 ]=> (define (isEven n) (if (< n 0) () (if (= n 0) #t (isOdd (- n 1))))) ;Value: iseven 1 ]=> (isEven 5) ;Value: () 1 ]=> (isOdd 5) ;Value: #t D. Rösner PGP 2009 . . . 18 Funktionales Programmieren Scheme Lokale Definitionen Motivation: Vermeiden wiederholter Berechnungen klarer strukturierter Code Beispiel: eine Funktion addPairwise’, die korrespondierende Elemente zweier Zahlenlisten addiert und – falls eine Liste keine Elemente mehr hat – den aktuellen Rest der anderen an die Liste der Paarsummen anhängt D. Rösner PGP 2009 . . . 19 Funktionales Programmieren Scheme Scheme: lokale Bindungen mit let und let* Syntax: (let ((var1 val1) (var2 val2) ... (varN valN)) <body>) Semantik: bei der Auswertung von <body> sind die in var1, var2, ..., varN gebundenen Werte val1, val2, ..., valN verfügbar D. Rösner PGP 2009 . . . 20 Funktionales Programmieren Scheme Scheme: lokale Bindungen mit let und let* Beispiel: addPairwiseRest als Äquivalent zu addPairwise’ (define (addPairwiseRest list1 list2) (let ((front (addPairwise list1 list2)) (minLength (min (length list1)(length list2)))) (let ((rear (append (drop minLength list1) (drop minLength list2)))) (append front rear)))) D. Rösner PGP 2009 . . . 21 Funktionales Programmieren Scheme Scheme: lokale Bindungen mit let und let* Beachte: bei let erfolgt die Auswertung und Bindung in den einzelnen (var1 val1) (var2 val2) ... (varN valN) parallel daher folgendes falsch: (define (addPairwiseRest list1 list2) (let ((front (addPairwise list1 list2)) (minLength (min (length list1)(length list2))) (rear (append (drop minLength list1) (drop minLength list2)))) (append front rear))) 1 ]=> (addPairwiseRest ’(4 7 1 1 ) ’(8 15)) ;Unbound variable: minlength D. Rösner PGP 2009 . . . 22 Funktionales Programmieren Scheme Scheme: lokale Bindungen mit let und let* let* ist wie let, nur erfolgt Auswertung und Bindung in den einzelnen (var1 val1) (var2 val2) ... (varN valN) sequentiell m.a.W. für die Ausdrücke vali (für 2 <= i <= n) stehen die Bindungen var1, var2, ..., var(i-1) zur Verfügung D. Rösner PGP 2009 . . . 23 Funktionales Programmieren Scheme Scheme: lokale Bindungen mit let und let* Beispiel für let*: (define (addPairwiseRest list1 list2) (let* ((front (addPairwise list1 list2)) (minLength (min (length list1)(length list2))) (rear (append (drop minLength list1) (drop minLength list2)))) (append front rear))) 1 ]=> (addPairwiseRest ’(4 7 1 1 ) ’(8 15)) ;Value 12: (12 22 1 1) D. Rösner PGP 2009 . . . 24 Funktionales Programmieren Scheme Beispiel cont. Hilfsfunktionen a la Haskell: (define (addPairwise list1 list2) (if (or (null? list1)(null? list2)) () (cons (+ (car list1)(car list2)) (addPairwise (cdr list1)(cdr list2))))) (define (take n list) (if (= n 0) () (cons (car list) (take (- n 1) (cdr list))))) (define (drop n list) (if (= n 0) list (drop (- n 1) (cdr list)))) D. Rösner PGP 2009 . . . 25 Funktionales Programmieren Scheme Scheme: Berechnung Quadratwurzel mit Newton-Verfahren (define (sqrt x) (sqrt-iter 1 x)) (define (sqrt-iter guess x) (if (good-enough? guess x) guess (sqrt-iter (improve guess x) x))) (define (good-enough? guess x) (< (abs (- (square guess) x)) .001)) (define (improve guess x) (average guess (/ x guess))) D. Rösner PGP 2009 . . . 26 Funktionales Programmieren Scheme Blockstruktur: (define (sqrt x) (define (good-enough? guess x) (< (abs (- (square guess) x)) .001)) (define (improve guess x) (average guess (/ x guess))) (define (sqrt-iter guess x) (if (good-enough? guess x) guess (sqrt-iter (improve guess x) x))) (sqrt-iter 1 x) ) D. Rösner PGP 2009 . . . 27 Funktionales Programmieren Scheme Interne Definitionen Ausnutzen, daß x in sqrt gebunden (lexikalischer Skopus): (define (sqrt x) (define (good-enough? guess) (< (abs (- (square guess) x)) .001)) (define (improve guess) (average guess (/ x guess))) (define (sqrt-iter guess) (if (good-enough? guess) guess (sqrt-iter (improve guess)))) (sqrt-iter 1)) D. Rösner PGP 2009 . . . 28 Funktionales Programmieren Scheme lexikalischer Skopus: freie Variable in einer Prozedur verweisen auf Variable in umfassenden Prozeduren m.a.W.: Werte freier Variable werden in der Umgebung gesucht, in der die Prozedur definiert wurde D. Rösner PGP 2009 . . . 29 Funktionales Programmieren Scheme Literatur: I Harold Abelson, G.J.Sussman, and J.Sussman. Structure and Interpretation of Computer Programs. MIT Press, Cambridge, MA, USA, 1996. 2nd edition; Bem.: dt. Übersetzung existiert, aber engl. Original ist mehr zu empfehlen – DR. Michael Lee Scott. Programming Language Pragmatics. Academic Press, San Diego, CA, USA, 2000. ISBN 1-55860-578-9. D. Rösner PGP 2009 . . . 30 Funktionales Programmieren Scheme Literatur: II Ravi Sethi. Programming Languages – Concepts and Constructs. Addison-Wesley, Reading, Mass. USA, 1996. ISBN 0-201-59065-4. D. Rösner PGP 2009 . . . 31