Programmierparadigmen - Einführung in Scheme

Werbung
Funktionales Programmieren: Scheme
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 2011, 9. Juni 2011, 2011
D.Rösner
D. Rösner PGP 2011 . . .
1
Funktionales Programmieren: Scheme
Gliederung
1
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
D. Rösner PGP 2011 . . .
2
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Historie
Frage: Welches sind die zwei ältesten und (in
modernisierter Form) immer noch benutzten
Programmiersprachen?
...
...
Frage: Wann wurden diese Sprachen entwickelt?
...
D. Rösner PGP 2011 . . .
4
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Historie
unterschiedliche Ausrichtungen:
Fortran: numerische Berechnungen
Lisp: Symbolverarbeitung
Symbolverarbeitung?
Beispiele:
symbolisches Rechnen (z.B. Differentiation, Integration)
logisches Schliessen
Analyse und Synthese chemischer Formeln
Verarbeitung natürlicher Sprache
Repräsentation von Wissen (z.B. semantische Netze)
...
D. Rösner PGP 2011 . . .
5
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Symbolverarbeitung mit Lisp
Sprachmittel für Symbolverarbeitung in Lisp
Atome als elementare Bausteine
zusammengesetzte Strukturen auf der Basis
verschachtelter Listen
Beispiel: mögliche Darstellung eines Syntaxbaums
(S (NP (DET Der) (N Mann))
(VP (V fragt)
(PP (P nach)
(NP (DET dem) (N Weg)
(PP (P zum)
(NP (N Bahnhof)))))))
Scheme ist ein Dialekt von Lisp
D. Rösner PGP 2011 . . .
6
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 Assoziationen zwischen Namen und Werten
mit define
(define <name> <wert>)
D. Rösner PGP 2011 . . .
7
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Scheme als funktionale Sprache:
wichtig: 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 2011 . . .
8
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
9
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
10
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Scheme: Übersicht
vordefinierte Datentypen
Zahlen: ganze, rationale, Fliesskomma, ...
Strings: z.B. "ein String"
Zeichen: z.B. #\a #\Z #\* #\space
boolesche Werte: #t, #f
...
D. Rösner PGP 2011 . . .
11
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Scheme: Übersicht
wichtigster aggregierter Datentyp: Liste
Konstruktor: cons
Selektoren: car, cdr
Prädikate: list?, null?
wichtige Kontrollstrukturen:
if
cond
Funktionen zur Konversion zwischen verschiedenen Typen, z.B.
number->string
string->list
...
D. Rösner PGP 2011 . . .
12
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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
rein funktional (pur)?
Scheme: nicht pur, Seiteneffekte möglich z.B. mit set!
Haskell: pur
D. Rösner PGP 2011 . . .
14
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Scheme vs. Haskell
in Scheme: keine Typisierung
Typüberprüfung durch vor- oder eigendefinierte
Typprädikate
Beispiele:
number?
list?
string?
...
D. Rösner PGP 2011 . . .
15
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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.
s.a. [?], Ch. 11.2.2.
D. Rösner PGP 2011 . . .
16
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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
s.a. [?], Ch. 11.2.2.
in Scheme nicht vordefiniert vorhanden sind u.a.
Listenkomprehensionen und
Fallunterscheidung durch Pattern Matching
D. Rösner PGP 2011 . . .
17
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
18
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Scheme: Funktionen höherer Ordnung
map . . . Anwenden einer Funktion auf die Elemente einer
Liste und Rückgabe der Liste der Ergebnisse
> (define (map f l) (if (null? l) ’()
(cons (f (car l)) (map f (cdr l)))))
> (map (lambda (x) (* x x)) ’(2 3 4 5))
(4 9 16 25)
D. Rösner PGP 2011 . . .
20
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
21
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
22
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
24
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
25
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
26
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
27
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
28
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
29
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
30
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
31
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
32
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
34
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
35
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
36
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
37
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
39
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
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 2011 . . .
40
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Literatur: I
Michael Lee Scott.
Programming Language Pragmatics.
Academic Press, San Diego, CA, USA, 2000.
ISBN 1-55860-578-9.
D. Rösner PGP 2011 . . .
41
Herunterladen