Höhere Programmiersprachen

Werbung
Common Lisp
Lisp ist Urform aller funktionaler Sprachen
Datentypen: Liste (eigentlich Bäume), Atome“
”
Keine Operationen auf Atomen, ausser Vergleich
Programme sind symbolische Ausdrücke (S-expressions)
repräsentiert als Listen
Programme zur Laufzeit modifizierbar
Ursprung ist Lisp 1.5:
John McCarthy: Recursive Functions of Symbolic Expressions and their
Computation by Machine, Part I, Comm. of the ACM 3(1960), Nr. 4,
184-195
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
128 / 212
Common Lisp
Atom Zeichenreihe z ∈ S, spezielle Zeichenreihe nil ∈ S
Baum x, y ∈ S: cons[x, y ] = (x.y ) ∈ S
Liste (x1 x2 . . . xn ) = (x1 .(x2 .(. . . (xn .nil) . . . )))
x1
x2
xn
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
nil
Wintersemester 2005/2006
129 / 212
Grundfunktionen
t bezeichnet beliebigen Wert 6= nil, nil = falsch, t = wahr
atom : S −→ Bool
atom[X ] = t
atom[x.y ] = nil
eq : Atom × Atom −→ Bool
eq[X , X ] = t
eq[X , Y ] = nil
car : S −→ S
car[(x.y )] = x
cdr : S −→ S
cdr[(x.y )] = y
cons : S × S −→ S
cons[x, y ] = (x.y )
Alle anderen Fälle liefern nil
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
130 / 212
Grundfunktionen
(quote x) abgekürzt ’x: verhindert die Auswertung von x und liefert
x zurück
car und cdr kombinierbar
(cadddr ’(1 2 3 4 5 6 7 8)) = 4
(lambda (x) y) entspricht λx.y
Currying mit (lambda (x1 x2 ...) y)
(cond (x1,y1), (x2,y2),...,(xn,yn)) entspricht
if x1 6= nil then y1 else (cond (x2,y2) ...)
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
131 / 212
Der Sündenfall: Zuweisungen in Lisp
Alle heutigen Versionen von Lisp
(Emacs Lisp, Scheme, Common Lisp, . . . ) erlauben Zuweisungen:
Variablenvereinbarung:
(defvar variable)
(defvar variable anfangswert)
Zuweisung:
(set variable wert)
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
132 / 212
Quote & Zuweisungen in Lisp
Beispiel
(set ’one 1)
(set ’two ’one)
(set two 2)
; one => 1
; two => one
; one => 2
Häufig sieht man für
(set ’x y)
die Kurzform
(setq x y)
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
133 / 212
Common Lisp
Beispiel
Beispiel
(defun fact (x) (if (= x 0) 1 (* x (fact (- x 1)))))
Daher auch der Beiname: Lots of Irritating Superfluous Parentheses“
”
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
134 / 212
Lisp
Übersicht
Älteste funktionale Sprache
Moderne Dialekte: Scheme, Common Lisp, Emacs Lisp
Dynamisch typisiert
Erste Sprache mit automatischer Speicherbereinigung
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
135 / 212
ML (Metalanguage)
Als Programmiersprache für einen automatischen Beweiser (LCF)
entwickelt
1997 standardisiert ⇒ Standard ML
Formal vollständig definiert
Viele freie Übersetzer verfügbar
Standard ML of New Jersey
Poly ML
Moscow ML
OCaml
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
136 / 212
ML
Eigenschaften
Funktionen sind first class objects“
”
Strikte Auswertung
Starke Typisierung
Ausdrucksstarke zusammengesetzte Typen (Tupel, Verbunde)
Rekursive Datentypen
Typinferenz
Parametrische Polymorphie
Imperative Konstrukte
Modul-System
Automatische Speicherbereinigung
Ausnahmen
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
137 / 212
ML
Wertbindungen
val x = 3 bindet x an den Wert 3
x ist ein Name für einen Wert und repräsentiert keinen Speicherplatz
Somit kann man x nicht beschreiben, sondern nur einen neuen Wert
binden
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
138 / 212
ML
Datentypen
int Ganze Zahlen uneingeschränkter Länge
123
~123
real Gleitkommazahlen
0.01
2.7182818
~1.2E12
7E~5
bool true, false
string "Hallo"
Verkettung mit ^
Verbunde {a:T1, b:T2, ...}
val person = { name = "Hugo", age = 42 }
Tupel (1, 2, 3, 4)
sind eigentlich Verbunde {1:T, 2:T, ...}
#n liefert n-tes Element
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
139 / 212
ML
Datentypen
Verbunde {a:’a, b:’b, ...}
val person = { name = "Hugo", age = 42 }
Tupel (1, 2, 3, 4)
sind eigentlich Verbunde {1:’a, 2:’b, ...}
#n liefert n-tes Element
Listen
nil Synonym für []
:: entspricht cons bei Lisp
nil = []
9 :: [] = [9]
5 :: [9] = [5, 9]
3 :: [5, 9] = [3, 5, 9]
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
140 / 212
ML
Parametrische Polymorphie
ML unterstützt parametrische Polymorphie:
Beispiel
# fun
val K
# fun
val S
# fun
val I
K
=
S
=
I
=
x y = x;
fn : ’a -> ’b -> ’a
x y z = x z (y z);
fn : (’a -> ’b -> ’c) -> (’b -> ’c) -> ’a -> ’c
x = S K K x;
fn : ’a -> ’a
a’, b’, etc. kennzeichnen Typvariablen
a’ steht für α, b’ für β, etc.
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
141 / 212
ML
Eigene Datentypen
Eigene Datentypen durch Angabe der Konstruktoren:
Datentyp
::=
Konstruktor
::=
datatype Bezeichner =
Konstruktor [ | Konstruktor ]*
Bezeichner [ of Typausdruck ]
Beispiel
datatype Shape = Clubs | Spades | Hearts | Diamonds
datatype Term =
|
|
|
Const of int
Var of string
Add of Term * Term
Mul of Term * Term
datatype ’a BinTree = Lf
| Br of ’a * ’a BinTree * ’a BinTree
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
142 / 212
ML
Eigene Datentypen — Beispiele
Beispiel
val a_term = Plus(Mul(Const(3), Var("x")), Const(4))
val a_tree = Br("Node", Br("Left", Lf, Lf),
Br("Right", Lf, Lf))
Achtung
Konstruktor-Terme sind keine Funktionsaufrufe! Sie repräsentieren einen
Wert des definierten Datentyps
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
143 / 212
ML
Funktionen
Funktionen sind Werte
Sie können Ergebnis einer Berechnung sein
fn x => y entspricht λx.y
fun f x1 ...xn = y ist Abkürzung für
val f = fn x1 => ... => fn xn => y
Beispiel
# fun muladd z y x = x * y + z
val muladd = fn : int -> int -> int -> int
# val mul = muladd 0;
val mul = fn : int -> int -> int
# val erg = mul 2 3;
val erg = 6 : int
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
144 / 212
ML
Funktionen
Vergleich zu imperativen Sprachen
In C, Pascal, etc. können auch Funktionen auch Funktionen
zurückgeben und als Parameter nehmen (mittels Funktionszeiger)
C erlaubt jedoch keine geschachtelten Funktionen, aber Pascal und
Modula-3
Was passiert, wenn innere Funktionen auf Variablen der äußeren
zugreifen? Z.B.
Beispiel
val add = fn x => fn y => x + y;
val smallinc = add 1
Konzept vom Aufrufkeller nicht ausreichend
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
145 / 212
ML
Funktionen
val add = fn x => fn y => x + y;
x ist frei in fn y => x + y
Aufrufschachtel der äußeren Funktion nicht mehr verfügbar
Innere Funktion intern (sog. Closure)
Werte der freien Variablen × Funktionszeiger
Closures werden mittels automatischer Speicherbereinigung entfernt
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
146 / 212
ML
Mustervergleich — Pattern Matching
Unterstützung, um Konstruktor-Terme auf Passung zu untersuchen
Beispiel
fun
|
|
|
;
diff
diff
diff
diff
(Var(s))
(Const(_))
(Plus(a, b))
(Mul(a, b))
=
=
=
=
Const 1
Const 0
Plus(diff a, diff b)
Plus(Mul(diff a, b), Mul(a, diff b))
Auch als Fallunterscheidung“vorhanden
”
Beispiel
val s
0
| 1
| n
= case x of
=> "zero"
=> "one"
=> if n < 10 then "some" else "too many";
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
147 / 212
ML
Neue Operatoren
Ein gültiger Bezeicher besteht entweder
Nur aus Buchstaben, Zahlen und
(erstes Zeichen muss Buchstabe sein)
oder nur aus Sonderzeichen
Beispiel
fun &&*% x = x + 1;
Jede zweistellige Funktion kann infix
(sowohl links als auch rechts-assoziativ) verwendet werden
Bei infix-Funktionen auch Priorität änderbar!
Beispiel
infix 4 >>;
infixr 8 **;
fun x ** y = if y = 0 then 1 else x * (x ** (y - 1));
fun x >> y = x div 2 ** y;
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
148 / 212
ML
Funktionale – Higher order functions“
”
Sections
fun secl x f y = f(x, y)
val secl = fn : ’a -> (’a * ’b -> ’c) -> ’b -> ’c
fun secr y f x = f(x, y)
Beispiel
# fun hallo x = secl "Hallo " op^ x
# hallo "Du"
Verkettung
infix o
fun (f o g) x = f (g x)
val o = fn : (’b -> ’c) * (’a -> ’b) -> ’a -> ’c
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
149 / 212
ML
Funktionale – Higher order functions“
”
map fun map f []
| map f (x::xs)
= []
= (f x) :: map f xs;
Beispiel
val names = ["Horst", "Schorsch", "Peter"];
val greeted_names = map (secl "Hallo " op^) names;
foldl fun foldl f e []
| foldl f e (x::xs)
= e
= foldl f (f(e, x)) xs;
Beispiel
val sum = foldl op+ 0;
sum [1, 2, 3, 4, 5];
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
150 / 212
ML
Faule/strikte Auswertung
ML verwendet strikte Auswertung
bevor eine Funktion ausgeführt wird, werden alle Argumente
berechnet
Die eingebauten Konstrukte if B then X else Y, andalso und
orelse verwenden jedoch faule Auswertung.
if B then X else Y
X andalso Y
X orelse Y
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
≡
≡
≡
(fn true => X | false => Y) (B)
if X then Y else false
if X then true else Y
Höhere Programmiersprachen
Wintersemester 2005/2006
151 / 212
Faule Auswertung (call-by-need)
Faule Auswertung ist ähnlich zu Namensaufruf (call-by-name)
Bei fauler Auswertung jeder Ausdruck höchstens einmal ausgewertet
Argumentausdruck wird nicht, wie beim Namensaufruf, in den Rumpf
eingesetzt
Jedes Auftreten des Arguments wird mit einer Referenz auf den
Argumentausdruck versehen
Referenzen bilden einen gerichteten Graphen
Faule Auswertung eines Ausdrucks entspricht Graph-Reduktion
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
152 / 212
Faule Auswertung
Beispiel
fun sqr x = x * x
sqr(sqr(sqr(2)))
sqr
×
×
×
sqr
⇒ sqr
sqr
sqr
sqr
×
2
2
2
2
⇒
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
×
⇒
×
×
⇒
Höhere Programmiersprachen
×
×
⇒
16
256
⇒
4
Wintersemester 2005/2006
153 / 212
ML
Rekursion
Schleifen werden durch Rekursion ausgedrückt
Rekursion oft ineffizient, wegen der Kosten für Funktionsaufrufe
Beispiel
fun fac n = if n = 0 then 1 else n * fac (n - 1);
fac(2) wird wie folgt berechnet:
⇒ 2 * fac(2 - 1) = 2 * fac(1)
⇒ 2 * (1 * fac(1 - 1)) = 2 * (1 * fac(0))
⇒ 2 * (1 * 1)
⇒ 2 * 1
⇒ 2
Ergebnis eines rekursiven Aufrufs wird zur Berechnung
weiter verwendet: n * fac(n -1)
fac(2)
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
154 / 212
ML
Rekursion — Tail Calls“
”
Beispiel
fun fac’ n p = if n = 0 then p else fac’ (n - 1) (n * p)
Diese Definition berechnet dasselbe wie fac
Ergebnis des rekursiven Aufrufs wird nicht weiterverwendet
Rekursiver Aufruf leicht vom Übersetzer entfernbar
.L1:
cmp
je
mul
sub
jmp
n, 0
.L2
p = n, p
n = n, 1
.L1
.L2:
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
155 / 212
ML
Typinferenz
ML Programme sind statisch typisiert
Programmierer braucht Typen der Variablen (fast) nie anzugeben
ML berechnet für jeden Ausdruck einen allgemeinsten Typen
⇒ Typinferenz
Literatur:
Damas, Milner: Principal type-schemes for functional programs, POPL ’82
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
156 / 212
ML
Modul-Sprache
ML erlaubt Modularisierung durch Spezifikation abstrakter
Datentypen mit eigenen Namensräumen
ML wird häufig in Kernsprache und Modul-Sprache unterteilt
Hierbei gelten folgende Analogien
Kernsprache
Wert ≡
Typ ≡
Funktion ≡
Modul-Sprache
Struktur
Signatur
Funktor
Signatur Schnittstellenbeschreibung
Struktur Implementierung der Schnittstelle
Funktor Parametrisierbare Implementierungen (Funktionen auf
Implementierungen)
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
157 / 212
ML
Modul-Sprache
signature RING =
sig
type t;
val zero : t;
val sum : t * t -> t;
val prod : t * t -> t;
end;
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
158 / 212
ML
Modul-Sprache
structure Int : RING =
struct
type t
= int;
val zero
= 0;
fun sum(x, y) = x + y;
fun prod(x, y) = x * y;
end;
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
159 / 212
ML
Modul-Sprache
functor Matrix(R : RING) : RING =
struct
type t = R.t list list;
fun sum (rowsA, [ ])
= rowsA
| sum ([ ], rowsB)
= rowsB
| sum (rowsA, rowsB) = ListPair.map (ListPair.map R.sum)
(rowsA, rowsB);
end;
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
160 / 212
ML
Imperativ Programmieren
Referenz-Typen
val p = ref 5;
val q = ref 2;
p := !p + !q;
(* Referenz auf den Wert 5 *)
(* Dereferenzieren von q, q und Zuweisung
Zuweisung mit :=
Signatur := = fn : ’a ref * ’a -> unit
Achtung
Zwei unterschiedliche Referenzen sind nie gleich (bzgl. =)
# val p = ref x;
# val q = ref x;
# p = q (* false *)
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
161 / 212
ML
Imperativ Programmieren
Sequentielle Anweisungen
(E1; E2; ...; En)
While-Schleife:
while A do B ≡ if A then (B; while A do B) else ()
Beispiel
fun fac(n, res) =
let val ip = ref 0
in
res := 1;
while !ip < n do (
ip := !ip + 1;
res := !res * !ip)
end;
Prof. Dr. Dr. h.c. Gerhard Goos (IPD)
Höhere Programmiersprachen
Wintersemester 2005/2006
162 / 212
Herunterladen