Semantik und Analyse von funktionalen Programmen Aufgabenblatt

Werbung
Prof. Dr. Manfred Schmidt-Schauß
Künstliche Intelligenz/Softwaretechnologie
Fachbereich Informatik und Mathematik/ Institut für Informatik
Johann Wolfgang Goethe-Universität Frankfurt am Main
Semantik und Analyse von funktionalen Programmen
Wintersemester 2007/2008
Aufgabenblatt Nr. 1
Abgabe: Dienstag 11. Dezember 2007 vor! der Vorlesung
Aufgabe 1 (20 Punkte)
Implementiert man in Haskell Vektoren als Listen, d.h.
> data Vektor a = Vektor [a]
>
deriving (Eq)
so ergibt sich das Problem, dass Vektoren unterschiedlicher Länge verglichen werden können,
obwohl dies keinen Sinn macht. Phantomtypen bieten eine Möglichkeit, dieses Problem zu umgehen: Wir definieren zunächst Peano-Zahlen auf der Typ-Ebene1 :
> data Zero
> data Succ a
Jetzt können wir z.B. den Typ, der eine 0 repräsentiert, als Zero und den Typ, der die
4 repräsentiert, als Succ (Succ (Succ (Succ (Zero)))) darstellen. Wir fügen dem VektorDatentypen einen Parameter hinzu, der in der Datentypdefinition zwar nicht benötigt wird,
aber erlaubt, die Länge des Vektor im Typ zu speichern:
> data Vektor n a = Vektor [a]
>
deriving (Eq)
Z.B. wird der folgende Gleichheitstest bereits zur Compilezeit vom Typsystem abgewiesen:
*Main> let vektor1 = Vektor [1,2,3] :: Vektor (Succ (Succ (Succ (Zero)))) Int
*Main> let vektor2 = Vektor [1,2] :: Vektor (Succ (Succ (Zero))) Int
*Main> vektor1 == vektor2
<interactive>:1:11: Couldn’t match expected type ‘Succ Zero’ against inferred type ‘Zero’...
Allerdings wird immer noch Vektor [1,2] == Vektor [1,2,3] ausgeführt, wenn wir die Typen
nicht angeben oder irgendeinen Typen als erstes Argument der beiden Vektor-Typens einsetzen,
z.B.
*Main> (Vektor [1,2] :: (Vektor String Int)) == (Vektor [1,2,3] :: (Vektor String Int))
False
Um dies zu verhindern, führen wir eine Typklasse Peano (ohne Methoden) ein, und fügen gerade
nur Instanzen für mit Zero und Succ gebildete Typen hinzu.
> class Peano a
> instance Peano Zero
> instance (Peano a) => Peano (Succ a)
1
Für diese Definition werden die Glasgow-Extensions benötigt, diese können mit ghci -fglasgow-exts eingeschaltet werden.
1
Nun definieren wir eine Eq-Instanz für Vektoren, die erfordert, dass der erste Parameter n Instanz
der Klasse Peano ist, also mit Succ und Zero aufgebaut wurde.
> instance (Peano n, Eq a) => Eq (Vektor n a) where
>
(==) (Vektor as) (Vektor bs) = as == bs
Tatsächlich werden nun falsche Aufrufe vom Compiler abgewiesen:
*Main> Vektor [1,2] == Vektor [1,2,3]
<interactive>:1:0: Ambiguous type variable ‘n’ in the constraint:
‘Peano n’ arising from use of ‘==’ at <interactive>:1:0-29
*Main> (Vektor [1,2] :: (Vektor String Int)) == (Vektor [1,2,3] :: (Vektor String Int))
<interactive>:1:0: No instance for (Peano [Char]) ...
a) Implementieren Sie mit dem gleichen Vorgehen die Multiplikation von Matrizen, die durch
den folgenden Datentypen dargestellt werden:
> data Matrix n m a = Matrix [[a]]
Die Multiplikation sei nur dann erlaubt, wenn die Dimensionen n und m der beiden Matrizen
zueinander passen (es dürfen nur (n × m)- mit (m × k)-Matrizen multipliziert werden).
Falls die Dimensionen nicht zueinander passen, soll der Ausdruck bereits zur Compilezeit
einen Typfehler ergeben.
(15 Punkte)
b) Welche Nachteile ergeben sich aus Programmiersicht durch eine solche Verwendung von
Phantomtypen?
(5 Punkte)
Aufgabe 2 (30 Punkte)
Eine Gemeinschaftspraxis bestehe aus n Ärzten, die in FIFO-Reihenfolge auf Patienten warten.
Ankommende Patienten reihen sich ebenfalls in FIFO-Ordnung in eine Warteschlange ein. Die
Arzthelferin am Empfang verteilt je einen Patienten am Anfang der Patientenschlange“ auf
”
einen Arzt am Anfang der Ärzteschlange“. Wenn ein Arzt mit seiner Behandlung fertig ist,
”
reiht er sich hinten in die Ärzteschlange“ ein.
”
Modellieren und simulieren Sie die Arztpraxis für n Ärzte und m Patienten mithilfe von Concurrent Haskell, wobei folgendes gelten sollte:
• Die beiden Schlangen werden durch Kanäle modelliert (z.B. können sowohl Ärzte als auch
Patienten durch Zahlen simuliert werden).
• Im Hauptthread werden zunächst beide Schlangen leer erzeugt.
• Anschließend werden die beiden Schlangen durch nebenläufige Threads gefüllt.
• Der Hauptthread übernimmt nun die Aufgabe der Arzthelferin und verteilt die Patienten
auf die Ärzte.
• Eine Behandlung sollte nebenläufig durchgeführt werden und tatsächlich unterschiedlich viel Zeit benötigen. Hierfür können Sie threadDelay (aus dem Modul
Control.Concurrent) zum Verzögern des Threads und randomIO (aus dem Modul
System.Random) zum Erzeugen einer Zufallszahl verwenden.
• Zum Beginn der Behandlung (bevor die Verzögerung ausgeführt wird), soll auf dem Bildschirm noch ausgegeben werden, welcher Arzt welchen Patient wie lange behandelt.
• Am Ende der Behandlung muss der Arzt sich wieder in die Ärzteschlange einreihen.
2
Herunterladen