Funktionales Programmieren und die Sprache LISP

Werbung
Proseminar Funktionales Programmieren
Die Programmiersprache
LISP
Stephan Kreutzer
Teil I:
Funktionales Programmieren
Imperative Sprachen
Imperative Sprachen:
Befehlsorientiert
“Imperative Sprachen orientieren sich an der Arbeitsweise von Computern.”
Idee:
Durch Befehle wird der Zustand des Rechners verändert.
Typische Elemente: Zuweisungen: x = 3;
Schleifen:
for(int i=17; i!=0; i--) { ... }
Prozeduren:
int whatever(int x) { ... }
Zeiger:
int *y = &x;
*y = 19;
Explizite Speicherverwaltung:
int ar[] = malloc(17*sizeof(int));
free(ar);
Arrays:
ar[ 13] = ar[12]-3;
Typische Vertreter: C, Pascal, Fortran, Algol, ... Stephan Kreutzer
Proseminar Funktionales Programmieren
3
Funktionale Sprachen
Funktionale Sprachen:
Ausdrucksorientiert
“Funktionale Programme berechnen Ausdrücke.”
Idee:
Programme beschreiben Abbildungen (der Eingabe auf die Ausgabe)
Typische Elemente: Gleichheit:
let x = 3;;
Seiteneffektfrei, daher keine Zeiger, usw.
Funktionen:
let rec factorial = function n ->
if n = 0 then 1
else n * factorial (n-1);;
Implizite Speicherverwaltung (garbage collection)
Datenstrukturen: Listen und Bäume
(Rekursion)
Pattern Matching, Typinferenz, Funktionen höherer Ordnung...
Typische Vertreter:
Stephan Kreutzer
Haskell, ML und Nachfolger, (Scheme), (Lisp) Proseminar Funktionales Programmieren
4
Seiteneffekte
Seiteneffekte:
Betrachte C­Programm:
int global-var = 9;
int f(int x)
{
global-var = global-var + 1;
return x + global-var;
}
void main()
{
int x1 = f(5);
int x2 = f(5);
}
●
●
// x1 := 15
// x2 := 16;
Solche Zustandsveränderungen heißen Seiteneffekte.
Funktionale Programme sind “seiteneffektfrei” !
➢ Variablen sind keine Namen für Speicherstellen!
➢ Keine Zuweisungen
Stephan Kreutzer
Proseminar Funktionales Programmieren
5
Seiteneffekte
Betrachte OCaml­Programm:
let y = 3;;
(* Weist x den Wert 3 zu *)
let f = function n -> (y+n);;
(* Definiert Funktion f(n) = n+x*)
let x1 = f 3;;
(* Liefert 6 als Wert *)
let y = 10;;
(* Weist x den Wert 10 zu *)
let x2 = f 3;;
(* Liefert 6 als Wert *)
●
Variablen bezeichnen Werte, keine Speicherstellen!
●
Zweites let x = 10;; verändert die Definition von f nicht. ●
x ist also keine globale Variable, wie im C­Programm vorhin.
Vorteil: Seiteneffekte sind einer der häufigsten Fehlerquellen
Seiteneffekfreiheit eliminiert diese Fehlerquelle
Stephan Kreutzer
Proseminar Funktionales Programmieren
6
Schleifen und Rekursion
Schleifen in imperativen Programmen:
int ergebnis=0;
int ergebnis=0;
while (some-test(ergebnis))
{
ergebnis = some-function();
}
for (int i = 0; i<17; i++)
{
ergebnis = some-thing();
}
return ergebnis;
return ergebnis;
Schleifenabbruch erfolgt also über Seiteneffekte.
Dumm, wenn Seiteneffekte nicht erlaubt sind.
In funktionalen Programmen: Rekursion
let rec f = function ergebnis ->
if some-test(ergebnis) then f(some-function(ergebnis))
else ergebnis;;
Stephan Kreutzer
Proseminar Funktionales Programmieren
7
Listen
Für rekursive Programme ohne Speicherveränderung eignen sich besonders „ rekursive” Datenstrukturen, z.B. Listen oder Bäume.
let list = [1; 2; 3; 4];;
(* Definiert Liste 1,2,3,4 *)
let rec add = function
(* Addiert die Werte einer Liste *)
[]
-> 0
| n::r -> n + add r;;
Pattern
Matching
let result = add list;;
(* [] steht für leere Liste *)
(* n::r steht für Liste mit erstem
Element n und Rest r.
Beispiel:
[ 1; 2; 3; 4] = 1::[2; 3; 4]
*)
(* Liefert result = 10 als Ergebnis *)
Listen und Bäume gut geeignet, da typischerweise sequentieller Zugriff.
Weniger gut geeignet für funktionale Programme: Arrays
Hier erfolgt der Zugriff an beliebigen Positionen. Typischerweise Manipulation der Werte in einem Array.
Stephan Kreutzer
Proseminar Funktionales Programmieren
8
Teil II:
Common LISP
„ Common Lisp is a new dialect of Lisp, a successor to MacLisp [33, 37], in­
fluenced stronlgy by ZetaLisp [55, 34] and to some extend by Scheme [46]
and InterLisp [50].”
(Common Lisp the language, 2nd edition, Guy L. Steele)
LISP – List Processing
Lisp:
Akronym für “List Processing Language”
1956:
John McCarthy entwickelt Idee zu einer Sprache für algebraische Listenverarbeitung in der künstlichen Intelligenz.
Wie der Name schon andeutet, ist Lisp auf Listenverarbeitung spezialisiert.
Anders gesagt: Lisp verarbeitet eigentlich nur Listen.
Beispiele fü r Listen in Lisp: ( 1 2 3 4 )
( Name 2 )
( Name 2 (/ 2 3)
)
; Liste mit Elementen 1, 2, 3, 4
; Liste Student, Name, 2
; Liste Name, 2, Unterliste /, 2, 3
Name, 2 ... Symbole
Beachte, daß Name nicht in Anführungszeichen steht, ist also kein String!
In Listen können Elemente verschiedenen Typs vorkommen:
Lisp ist eine ungetypte Sprache!
(In Lisp haben Objekte einen Typ, Variablen aber nicht. Also kein '
int x;'
)
Stephan Kreutzer
Proseminar Funktionales Programmieren
10
Formen in Lisp
Lisp­Programme bestehen aus Formen, die ausgewertet werden.
Form: Entweder ein Atom oder eine Liste.
Atom:
Zahl:
123
Variable: x, 4h//34+, ...
Konstante: (defconst konstante 4)
Liste:
(list 'Listenelement­2 'Elem­3 'x)
(+ 4 5)
Auswertung von Listen:
Das erste Element wird als Funktion gewertet und auf die anderen Ele­
mente angewendet.
> (+ 4 5)
9
>(list 'x 3 'Name )
(x 3 Name)
Stephan Kreutzer
; Numerische Operationen in Präfix­Notation
; Bildet Liste mit Elementen x, 3, Name
Proseminar Funktionales Programmieren
11
Listen in Lisp
Listen:
(element1 element2 element3 ...)
Listenelemente werden durch ' ' getrennt.
Listenkonstruktoren:
(cons h r):
Bildet eine Liste mit Kopf h und Rest r
(cons 1 nil)
-> (1)
; nil steht für leere Liste
(cons 1 (cons 2 nil))
-> (1 2)
(cons 1 '(2))
-> (1 2)
'
: quote
Verhindert, daß Lisp versucht, '2' als Funktion auszuwerten.
(cons 1 (quote (2)))
Listen zerlegen:
(first '(1 2 3))
(rest '(1 2 3))
äquivalent zu (cons 1 '(2))
-> 1
; liefert das erste Element einer Liste
-> (2 3) ; liefert den 'Rest' einer Liste
(Man beachte wieder die quotes)
(rest (list 1 2 3))
Stephan Kreutzer
-> (2 3) ; liefert den 'Rest' einer Liste
Proseminar Funktionales Programmieren
12
Einfache Sprachelemente (Spezielle Formen)
Variablenzuweisung:
(setq x wert)
Weist x den Wert 'wert' zu Dabei wird das erste Argument 'x' nicht ausgewertet
(setq x 123)
(setq x '(1 2 3))
; Weist x die Zahl 123 zu
; Weist x die Liste ( 1 2 3 ) zu
Bedingte Verzweigung:
(if test w1 w2)
Wertet zu w1 aus, wenn 'test' erfüllt ist, sonst zu w2.
(if (= 1 1) (+ 3 4) "String" )
Conditional:
(cond (t1 v1) (t2 v2) ...)
Wertet zu vi aus, wenn Test ti erfüllt ist. (Erster erfüllter Test)
(cond ((= 1 1) "String") ((= 2 3) Symbol) (t 123))
Stephan Kreutzer
Proseminar Funktionales Programmieren
13
Funktionen
Funktionsdefinition:
(defun funktion (p1 p2 ...) (Funktionsrumpf))
Definiert Funktion 'funktion' mit Parametern p1 p2 ....
“ Hello World” :
> (write “Hello World!”)
Hello World!
Fakultä tsfunktion:
> (defun factorial
(n)
(cond ((= n 0)
(t
1)
(* n (factorial (- n 1))))))
FACTORIAL
Addieren der Elemente einer Liste:
(defun add (l) (cond
Stephan Kreutzer
( (eq l () ) 0)
(
t
(+ (first l) (add (rest l))))))
Proseminar Funktionales Programmieren
14
Ein­ und Ausgabe
Eingabe:
Liest Eingabe von der Standardeingabe
(read)
(setq x (read))
Liest eine Eingabe und weist sie der Variabel x zu
Ausgabe:
(write “Hello World!”)
Besonderheiten:
'read' liefert einen Lisp­Ausdruck zurück, keine Zeichenkette. > (read)
Dies ist eine Zeichenkette!
*** - EVAL: variable IST has no value
Nü tzlich in Verbindung mit 'eval':
(eval w)
wertet den Ausdruck 'w' aus.
(eval '(setq x 10))
weist x den Wert 10 zu
Betrachte:
> (eval (read))
(setq x 100)
Liest Eingabe und wertet sie aus, d.h. weist x den Wert 100 zu.
Man spart sich also den Parser!
Stephan Kreutzer
Proseminar Funktionales Programmieren
15
Ein Beispiel
Datenbank:
(setq datenbank '((father Homer Bart)
(father Homer Lisa)
(son Bart Homer)))
Programm:
> (eval (read))
(cons '(daughter Lisa Homer) datenbank)
Fügt den Eintrag '(daugther Lisa Homer)' der Datenbank hinzu.
Werden jetzt noch Funktionen wie 'remove' und 'lookup' definiert, entsteht in wenigen Zeilen ein Programm zur Verwaltung einer einfachen Abstam­
mungsdatenbank!
Man vergleiche dies mit einem äquivalenten Program in C oder Java!
Bisher liest das Programm allerdings nur eine einzelne Eingabe.
Es fehlt ein Wiederholungsmechanismus! Stephan Kreutzer
Proseminar Funktionales Programmieren
16
Schleifen
"There'
s no such thing as an infinite loop. Eventually, the computer will break." ­­ John D. Sullivan
Loop­Schleife:
(loop (body))
Wiederholt unendlich oft den Schleifenrumpf '
(body)'
Abbruch der Schleife:
bricht die Schleife mit Wert '
wert'
ab.
(return wert)
Weitere Schleifen:
(dotimes (n Zahl) (body1) (body2) ...)
> (dotimes (n 11)
0 0
1 1
2 4
3 9
4 16
...
(print n)
Äquivalent einer '
for'
­Schleife
(print (* n n)))
Es gibt noch andere Schleifenkonstrukte.
Stephan Kreutzer
Proseminar Funktionales Programmieren
17
Ein Beispiel
Datenbank:
(setq datenbank '((father Homer Bart)
(father Homer Lisa)
(son Bart Homer)))
Programm:
> (loop (eval (read)))
(cons '(daughter Lisa Homer) datenbank)
Fügt den Eintrag '(daugther Lisa Homer)' der Datenbank hinzu.
Mit der Schleife ist sind nun beliebige viele Datenbankoperationen möglich.
Die Lisp­TopLoop:
(loop (write (eval (read))))
Liest endlos einen Lisp­Ausdruck von der Standardeingabe, wertet in aus
und gibt das Ergebnis auf dem Bildschirm aus.
Stephan Kreutzer
Proseminar Funktionales Programmieren
18
Basistypen in Lisp
Zahlen:
BIGNUM:
RATIO:
FIXNUM:
FLOAT:
Ganze Zahlen beliebiger Stelligkeit (beschr. durch Speicher)
Rationale Zahlen
(* 3 (/ 1 2))
->
3/2
Integers (Größe maschinenabhängig. Entspr. int)
Gleitkommezahlen (maschinenabhängig)
Lisp benutzt Präfixnotation (da in Listen erstes Symbol Funktion sein muß)
Zeichenketten:
STRING:
Zeichenketten
CHAR:
Einzelne Zeichen ( #\a steht für Buchstaben 'a')
Lisp ist ungetypt, d.h. Variablen haben keinen Typ (also kein BIGNUM x).
Natürlich kann auch Lisp keine Zahlen zu Wörtern addieren.
> (defun f (n) (+ n "Hallo"))
; Def. Funktion die n zu „Hallo” add.
F
; Lisp akzeptiert Definition.
> (f 3)
*** - +: "Hallo" is not a NUMBER
Stephan Kreutzer
Proseminar Funktionales Programmieren
19
Herunterladen