to get the file

Werbung
Scheme als funktionale Sprache:
Scheme als funktionale Sprache:
• Funktionen Objekte erster Ordnung
• Diskussion von Scheme im Vergleich mit Haskell
1 ]=> (define pi 3.1415)
;Value: pi
• m.a.W. Gemeinsamkeiten und Unterschiede
• Haskell als ‘Blaupause’ für funktionale Sprachen
1 ]=> pi
;Value: 3.1415
Grundlegendes:
1 ]=> (define quadriere (lambda (zahl) (* zahl zahl)))
;Value: quadriere
• Interpreter
• Definition von Werten mit define
1 ]=> (quadriere pi)
;Value: 9.86902225
(define <name> <wert>)
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 209
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), Scheme: Anonyme Funktionen
210
Scheme: Anonyme Funktionen
alternative Syntax für benannte Funktionen
• Syntax:
• (define (<name> <par-1> ... <par-n>) <koerper>)
(lambda <parameterliste> <koerper>)
• überall dort verwendbar, wo auch mit Symbol auf Funktion verwiesen werden kann
1 ]=> ((lambda (n) (* n n)) 3)
• statt
(define <name>
(lambda (<par-1> ... <par-n>) <koerper>))
;Value: 9
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 211
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 212
Scheme vs. Haskell
Scheme: Übersicht
• in Scheme: Klammerung innerhalb geschachtelter Ausdrücke; in Haskell:
Vorrangregeln
• vordefinierte Datentypen
– Zahlen: ganze, rationale, Fliesskomma, ...
– Strings
– Zeichen
– boolesche Werte: #t, #f
• in Scheme: keine Typisierung; in Haskell: strenge Typisierung
• Scheme: strikt; Haskell: non-strikt
• wichtigster aggregierter Datentyp: Liste
– Konstruktor: cons
– Selektoren: car, cdr
– Prädikate: null?
• in Scheme nicht vordefiniert vorhanden sind u.a. Listenkomprehension
und Fallunterscheidung durch Pattern Matching
• Kontrollstrukturen:
– if
– cond
• 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
• Funktionen zur Konversion zwischen verschiedenen Typen
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 213
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), Striktheit vs. Non-Striktheit
Scheme: Programm-Daten-Äquivalenz
• 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.
• Programme haben die Form von Listen
• Scheme (und Lisp) sind homoikonisch, d.h. selbstrepräsentierend
• Programme können mit allen Listenfunktionen bearbeitet werden
• Beispiel:
• Eine Sprache heisst strikt, wenn gefordert wird, dass alle ihre Funktionen
strikt.
(define compose
(lambda (f g)
(lambda (x) (f (g x)))))
• Eine Sprache heisst non-strikt, wenn sie die Definition non-strikter Funktionen zulässt.
1 ]=> ((compose car cdr) ’(1 2 3))
;Value: 2
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 214
215
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 216
Scheme: weitere Aspekte
Scheme: Programm-Daten-Äquivalenz
• Funktionen mit beliebiger Anzahl von Argumenten möglich (sog. Restparameter, der an Liste gebunden)
• Beispiel cont.:
(define compose2
(lambda (f g)
(eval (list ’lambda ’(x) (list f (list g ’x)))
(scheme-report-environment 5))))
• Beispiel:
(define (avg . nums) (average nums))
1 ]=> ((compose2 car cdr) ’(1 2 3))
• average erwartet Liste als Argument
;Value: 2
• Definition:
(define (average nums)(/ (apply + nums) (length nums)))
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 217
Scheme: Funktionen höherer Ordnung
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 218
Scheme: Funktionen höherer Ordnung
• z.B. Falten einer zweistelligen Funktion in eine Liste:
• partielle Anwendungen sind bei Funktionen im Curry-Format möglich
(define fold
(lambda (f l i)
(if (null? l) i ;; identity for f
(f (car l) (fold f (cdr l) i)))))
(define curry
(lambda (f) (lambda (a) (lambda (b) (f a b)))))
1 ]=> (((curry +) 3) 4)
;Value: 7
(define curried-plus (curry +))
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 219
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 220
Prozeduren und Prozesse:
Prozeduren und Prozesse:
Beispiel: Berechnung Fakultät
Beispiel: Berechnung Fakultät als linear-rekursiver Prozess
Definition: n! = n * (n - 1) * . . . * 2 *1
(factorial 6)
(* 6 (factorial 5))
(* 6 (*5 (factorial 4)))
(* 6 (*5 (* 4 (factorial 3))))
(* 6 (*5 (* 4 (* 3 (factorial 2)))))
(* 6 (*5 (* 4 (* 3 (* 2 (factorial 1))))))
(* 6 (*5 (* 4 (* 3 (* 2 1)))))
(* 6 (*5 (* 4 (* 3 2))))
(* 6 (*5 (* 4 6)))
(* 6 (*5 24))
(* 6 120)
720
Zusammenhang: n! = n * (n - 1)!
(define (factorial n)
(if (= n 1)
1
(* n (factorial (- n 1)))))
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 221
Beispiel: Berechnung Fakultät als linear-iterativer Prozess
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 222
Beispiel: Berechnung Fakultät als linear-iterativer Prozess
in jedem Schritt:
(factorial 6)
(fact-iter
1 1 6)
(fact-iter
1 2 6)
(fact-iter
2 3 6)
(fact-iter
6 4 6)
(fact-iter 24 5 6)
(fact-iter 120 6 6)
(fact-iter 720 7 6)
720
product <-- counter * product
counter <-- counter + 1
(define (factorial n) (fac-iter 1 1 n))
(define (fact-iter product counter max-count)
(if (> counter max-count)
product
(fact-iter (* counter product)
(+ counter 1)
max-count)))
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 223
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 224
Scheme vs. Haskell:
Scheme vs. Haskell: Sichtbarkeit von Definitionen
Sichtbarkeit von Definitionen
Beispiel cont.:
• die Definitionen auf dem Toplevel von Scheme sind ‘global’ sichtbar
1 ]=> (define (isEven n)
(if (< n 0) () (if (= n 0) #t (isOdd (- n 1)))))
• wechselseitige Bezugnahme in rekursiven Definitionen ist möglich
;Value: iseven
• Beispiel:
1 ]=> (isEven 5)
1 ]=> (define (isOdd n) (if (<= n 0) () (isEven (- n 1))))
;Value: ()
;Value: isodd
...
1 ]=> (isOdd 5)
;Value: #t
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 225
Lokale Definitionen
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 226
Scheme: lokale Bindungen mit let und let*
Motivation:
• Syntax: (let ((var1 val1) (var2 val2) ... (varN valN)) <body>)
• Vermeiden wiederholter Berechnungen
• Semantik:
bei der Auswertung von <body> sind die in var1, var2, ..., varN gebundenen
Werte val1, val2, ..., valN verfügbar
• klarer strukturierter Code
• Beispiel: addPairwiseRest als Äquivalent zu addPairwise’
• 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
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 227
(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))))
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 228
Scheme: lokale Bindungen mit let und let*
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
• let* ist wie let, nur erfolgt Auswertung und Bindung in den einzelnen
(var1 val1) (var2 val2) ... (varN valN) sequentiell
• daher folgendes falsch:
• 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
(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
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 229
Scheme: lokale Bindungen mit let und let*
230
Beispiel cont.
• Hilfsfunktionen a la Haskell:
• 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))
(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))))
;Value 12: (12 22 1 1)
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 231
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 232
Blockstruktur:
Scheme: Berechnung Quadratwurzel mit Newton-Verfahren
(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)))
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 233
Interne Definitionen
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 234
lexikalischer Skopus:
Ausnutzen, daß x in sqrt gebunden (lexikalischer Skopus):
• freie Variable in einer Prozedur verweisen auf Variable in umfassenden
Prozeduren;
(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))))
• m.a.W.: Werte freier Variable werden in der Umgebung gesucht, in der die
Prozedur definiert wurde
(sqrt-iter 1))
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 235
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 236
Ströme: Motivation
Ströme: Sprachmittel in SCHEME
• Berechnungen auf Kollektionen von Daten
• Konstruktor: cons-stream
• abstrakt gesehen: Sequenz von Datenobjekten
• Selektoren: head, tail
• mögl. Implementation: durch Listen
• Beziehung: für bel. a,b und x:
Wenn x ist (cons-stream a b), dann (head x) ist a und (tail x)
ist b.
• bessere Implementation: mit verzögerter Auswertung
Ströme repräsentieren den zeitlichen Verlauf der durch sie modellierten Systeme
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 237
Ströme: Implementation
• Konstante: the-empty-stream
• Prädikat: empty-stream?
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 238
Implementation cont.
• Implementation von Strömen durch verzögerte Evaluation (delayed evaluation, lazy evaluation)
• in normalen Listen: car und cdr werden zur Konstruktionszeit evaluiert
• in Strömen: tail erst zur Zugriffszeit evaluieren (call-by-need)
• (cons-stream <a><b>) . . . Spezialform, die gleichwertig mit
(cons <a> (delay <b>))
– d.h. Strom wird als Paar dargestellt
– im cdr steht promise zur Berechnung des tail
• (define (head stream) (car stream))
• Spezialform delay:
(delay <exp>) . . . liefert ein verzögertes Objekt, sog. promise, dass erst
mit force zur Ausführung veranlasst wird
• (define (tail stream) (force (cdr stream)))
• (force <promise>) . . . veranlasst Ausführung von <promise>
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 239
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 240
Unendlich lange Ströme
Unendlich lange Ströme cont.
Sieb des Eratosthenes
• Strom positiver ganzer Zahlen
(define (sieve stream)
(cons-stream
(head stream)
(sieve
(filter
(lambda (x) (not (divisible? x (head stream))))
(tail stream)))))
(define (integers-starting-from n)
(cons-stream n (integers-starting-from (1+ n))))
(define integers (integers-starting-from 1))
• Strom von Fibonacci-Zahlen
(define (fibgen a b)
(cons-stream a (fibgen b (+ a b))))
(define primes (sieve (integers-starting-from 2)))
(define fibs (fibgen 0 1))
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 241
Implizit definierte Ströme
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 242
Implizit definierte Ströme cont.
Hilfsfunktion: Elementweises Addieren zweier Ströme
• Strom positiver ganzer Zahlen
(define (add-streams s1 s2)
(cond ((empty-stream? s1) s2)
((empty-stream? s2) s1)
(else
(cons-stream
(+ (head s1)(head s2))
(add-streams (tail s1) (tail s2))))))
(define ones (cons-stream 1 ones))
(define integers
(cons-stream 1 (add-streams ones integers)))
• Strom der Fibonacci-Zahlen
(define fibs
(cons-stream 0
(cons-stream 1
(add-streams (tail fibs) fibs))))
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 243
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 244
Funktionale Programmierung: Haskell
Funktionale Programmierung: Scheme
• rein funktional
• funktional und imperative Elemente
• non-strikt
• strikt
• strenge Typisierung
• keine Typisierung
• lazy evaluation
• eager evaluation (aber: delay)
• Listenkomprehension
• –
• –
• Programm-Daten-Äquivalenz
• Pattern matching in Definitionen
• –
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 245
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), Rein funktionale Sprachen
Funktionskomposition als Sprachmittel
• in Scheme:
• Programmieren ohne Seiteneffekte
(define (compose f1 f2) (lambda (x) (f1 (f2 x))))
• Seiteneffekte können Programme schwer zu lesen und schwer zu kompilieren machen
• Abwesenheit von Seiteneffekten:
– Ausdrücke sind referentiell transparent – unabhängig von Ausführungsordnung
– Denken in Gleichungen möglich
– Gleichheit zweier Ausdrücke ist nicht zeitabhängig
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 246
247
• Beispiel für Anwendung:
(define
(define
(define
(define
(flatten tree) ...)
(remove-duplicates list) ...)
list-of-atoms (compose remove-duplicates flatten))
nr-of-atoms (compose length list-of-atoms))
; 1 ]=> tree
;Value 6: ((a (b (c d) e) (b f g) h (c d)))
; 1 ]=> (list-of-atoms tree)
;Value 7: (a e b f g h c d)
; 1 ]=> (nr-of-atoms tree)
;Value: 8
c Prof. Dr. D. Rösner; erstellt: 3. Juli 2007
Sommer 2007, Programmierparadigmen (PGP), 248
Herunterladen