Programmierparadigmen - Einführung in Scheme

Werbung
Funktionales Programmieren: Scheme
Funktionales Programmieren: Scheme
Gliederung
Programmierparadigmen
Einführung in Scheme
1
D. Rösner
Institut für Wissens- und Sprachverarbeitung
Fakultät für Informatik
Otto-von-Guericke Universität Magdeburg
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
c
Sommer 2011, 9. Juni 2011, 2011
D.Rösner
D. Rösner PGP 2011 . . .
Funktionales Programmieren: Scheme
D. Rösner PGP 2011 . . .
1
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Funktionales Programmieren: Scheme
Historie
2
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Historie
unterschiedliche Ausrichtungen:
Fortran: numerische Berechnungen
Frage: Welches sind die zwei ältesten und (in
modernisierter Form) immer noch benutzten
Programmiersprachen?
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)
...
Frage: Wann wurden diese Sprachen entwickelt?
...
D. Rösner PGP 2011 . . .
4
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
Funktionales Programmieren: Scheme
Symbolverarbeitung mit Lisp
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Scheme als funktionale Sprache:
Sprachmittel für Symbolverarbeitung in Lisp
Diskussion von Scheme im Vergleich mit Haskell
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)))))))
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>)
Scheme ist ein Dialekt von Lisp
D. Rösner PGP 2011 . . .
Funktionales Programmieren: Scheme
D. Rösner PGP 2011 . . .
6
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Funktionales Programmieren: Scheme
Scheme als funktionale Sprache:
7
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Scheme: Anonyme Funktionen
wichtig: Funktionen sind Objekte erster Ordnung
eine Interaktion:
Syntax:
(lambda <parameterliste> <koerper>)
überall dort verwendbar, wo auch mit Symbol auf Funktion
verwiesen werden kann
1 ]=> (define pi 3.1415)
;Value: pi
1 ]=> pi
;Value: 3.1415
1 ]=> ((lambda (n) (* n n)) 3)
1 ]=> (define quadriere
(lambda (zahl) (* zahl zahl)))
;Value: quadriere
;Value: 9
1 ]=> (quadriere pi)
;Value: 9.86902225
D. Rösner PGP 2011 . . .
8
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
Funktionales Programmieren: Scheme
Scheme: Anonyme Funktionen
Scheme: Übersicht
vordefinierte Datentypen
alternative Syntax für benannte Funktionen
Zahlen: ganze, rationale, Fliesskomma, ...
Strings: z.B. "ein String"
Zeichen: z.B. #\a #\Z #\* #\space
boolesche Werte: #t, #f
...
(define (<name> <par-1> ... <par-n>) <koerper>)
statt
(define <name>
(lambda (<par-1> ... <par-n>) <koerper>))
D. Rösner PGP 2011 . . .
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
D. Rösner PGP 2011 . . .
10
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Funktionales Programmieren: Scheme
Scheme: Übersicht
11
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Scheme vs. Haskell
Syntax:
wichtigster aggregierter Datentyp: Liste
in Scheme: Klammerung innerhalb geschachtelter
Ausdrücke
in Haskell: Vorrangregeln, Layoutregel
Konstruktor: cons
Selektoren: car, cdr
Prädikate: list?, null?
Typisierung?
wichtige Kontrollstrukturen:
in Scheme: keine Typisierung;
in Haskell: strenge Typisierung
if
cond
Striktheit?
Scheme: strikt
Haskell: non-strikt
Funktionen zur Konversion zwischen verschiedenen Typen, z.B.
number->string
string->list
...
D. Rösner PGP 2011 . . .
rein funktional (pur)?
Scheme: nicht pur, Seiteneffekte möglich z.B. mit set!
Haskell: pur
12
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
Funktionales Programmieren: Scheme
Scheme vs. Haskell
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.
in Scheme: keine Typisierung
Typüberprüfung durch vor- oder eigendefinierte
Typprädikate
Beispiele:
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.
number?
list?
string?
...
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 . . .
Funktionales Programmieren: Scheme
15
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
D. Rösner PGP 2011 . . .
Funktionales Programmieren: Scheme
Scheme vs. Haskell
16
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Scheme: weitere Aspekte
Art der Auswertung?
Funktionen mit beliebiger Anzahl von Argumenten möglich
(sog. Restparameter, der an Liste gebunden)
Beispiel:
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.
(define (avg . nums) (average nums))
average erwartet Liste als Argument
Definition:
in Scheme nicht vordefiniert vorhanden sind u.a.
(define (average nums)
(/ (apply + nums) (length nums)))
Listenkomprehensionen und
Fallunterscheidung durch Pattern Matching
D. Rösner PGP 2011 . . .
17
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
Funktionales Programmieren: Scheme
Scheme: Funktionen höherer Ordnung
Scheme: Funktionen höherer Ordnung
map . . . Anwenden einer Funktion auf die Elemente einer
Liste und Rückgabe der Liste der Ergebnisse
z.B. Falten einer zweistelligen Funktion in eine Liste:
> (define (map f l) (if (null? l) ’()
(cons (f (car l)) (map f (cdr l)))))
(define fold
(lambda (f l i)
(if (null? l) i ;; identity for f
(f (car l) (fold f (cdr l) i)))))
> (map (lambda (x) (* x x)) ’(2 3 4 5))
(4 9 16 25)
D. Rösner PGP 2011 . . .
Funktionales Programmieren: Scheme
20
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
D. Rösner PGP 2011 . . .
Funktionales Programmieren: Scheme
Scheme: Funktionen höherer Ordnung
21
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Scheme vs. Haskell:
partielle Anwendungen sind bei Funktionen im
Curry-Format möglich
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))))
(define curry
(lambda (f) (lambda (a) (lambda (b) (f a b)))))
1 ]=> (((curry +) 3) 4)
;Value: 7
;Value: isodd
...
(define curried-plus (curry +))
D. Rösner PGP 2011 . . .
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
22
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
Funktionales Programmieren: Scheme
Scheme vs. Haskell: Sichtbarkeit von Definitionen
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Lokale Definitionen
Beispiel cont.:
1 ]=> (define (isEven n)
(if (< n 0) ()
(if (= n 0) #t (isOdd (- n 1)))))
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
;Value: iseven
1 ]=> (isEven 5)
;Value: ()
1 ]=> (isOdd 5)
;Value: #t
D. Rösner PGP 2011 . . .
Funktionales Programmieren: Scheme
25
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
D. Rösner PGP 2011 . . .
Funktionales Programmieren: Scheme
Scheme: lokale Bindungen mit let und let*
26
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
Scheme: lokale Bindungen mit let und let*
Syntax:
Beispiel: addPairwiseRest als Äquivalent zu
addPairwise’
(let ((var1 val1)
(var2 val2)
... (varN valN))
<body>)
(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))))
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
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
Funktionales Programmieren: Scheme
Scheme: lokale Bindungen mit let und let*
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:
let* ist wie let, nur erfolgt Auswertung und Bindung in
den einzelnen (var1 val1) (var2 val2) ...
(varN valN) sequentiell
(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)))
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
1 ]=> (addPairwiseRest ’(4 7 1 1 ) ’(8 15))
;Unbound variable: minlength
D. Rösner PGP 2011 . . .
Funktionales Programmieren: Scheme
29
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
D. Rösner PGP 2011 . . .
Funktionales Programmieren: Scheme
Scheme: lokale Bindungen mit let und let*
30
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)))))
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)))
(define (take n list)
(if (= n 0) ()
(cons (car list) (take (- n 1) (cdr list)))))
1 ]=> (addPairwiseRest ’(4 7 1 1 ) ’(8 15))
;Value 12: (12 22 1 1)
D. Rösner PGP 2011 . . .
(define (drop n list)
(if (= n 0) list
(drop (- n 1) (cdr list))))
31
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
Funktionales Programmieren: Scheme
Scheme: Berechnung Quadratwurzel mit
Newton-Verfahren
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)))
(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))
(sqrt-iter 1 x)
)
(define (improve guess x)
(average guess (/ x guess)))
D. Rösner PGP 2011 . . .
Funktionales Programmieren: Scheme
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
34
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
D. Rösner PGP 2011 . . .
Funktionales Programmieren: Scheme
Interne Definitionen
35
Einführung
Scheme vs. Haskell
Funktionen höherer Ordnung
Skopus
Beispiel: Newton-Verfahren
Programm-Daten-Äquivalenz
lexikalischer Skopus:
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))))
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
(sqrt-iter 1))
D. Rösner PGP 2011 . . .
36
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
Funktionales Programmieren: Scheme
Scheme: Programm-Daten-Äquivalenz
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
Beispiel cont.:
Scheme (und Lisp) sind homoikonisch, d.h.
selbstrepräsentierend
(define compose2
(lambda (f g)
(eval (list ’lambda ’(x) (list f (list g ’x)))
(scheme-report-environment 5))))
Programme können mit allen Listenfunktionen bearbeitet
werden
Beispiel:
1 ]=> ((compose2 car cdr) ’(1 2 3))
(define compose
(lambda (f g)
(lambda (x) (f (g x)))))
;Value: 2
1 ]=> ((compose car cdr) ’(1 2 3))
;Value: 2
D. Rösner PGP 2011 . . .
Funktionales Programmieren: Scheme
39
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
D. Rösner PGP 2011 . . .
40
Herunterladen