TU Wien:Funktionale Programmierung VU (Knoop)/Prüfung 2023-03-03 (Lösungsvorschlag)
Zur Navigation springen
Zur Suche springen
Lösungsvorschlag von Dublbro[Bearbeiten | Quelltext bearbeiten]
Aufgabe 1 (2*0.5+8+4+2+2 = 17 Punkte)[Bearbeiten | Quelltext bearbeiten]
Vorgegebener Code:
data Liste a = Ende | E a (Liste a)
revertiere :: (Liste a) -> (Liste a)
- Ergebnisse der Aufrufe von (a) und (b):
- (a):
E 2 (E 5 (E 2 (E 3 (E 7)))) - (b):
E "Viel" (E "Er" (E "folg!" Ende))
- (a):
- Implementierung der Funktion:
revertiere Ende = Ende revertiere (E x l) = haenge_an x (revertiere l) haenge_an :: a -> (Liste a) -> (Liste a) haenge_an x Ende = E x Ende haenge_an x (E y l) = E y (haenge_an x l)
- Erklärung:
Die Funktionrevertiererevertiert eine Liste mit n Elementen, indem sie die hinteren n-1 Elemente revertiert und das erste Element hinten an diese anhängt. - Ad-hoc Polymorphie: Eine Funktion ist ad-hoc polymorph wenn die Typen eines oder meherer ihrer Parameter durch Typkontexte eingeschänkt sind.
- Mikroskopische Ebene - Lineare Rekursion: revertiere ruft sich pro Zweig höchstens ein Mal auf und davon ist ein Aufruf nicht die äußerste Operation.
Aufgabe 2 (2*0.5+2+(6+8)+(3+4)+5*2 = 34 Punkte)[Bearbeiten | Quelltext bearbeiten]
Vorgegebener Code:
data Liste a = Ende | E a (Liste a) deriving Show
f :: Ord a => (Liste a) -> (Liste a)
f = h . g
data Baum a = Blatt
| Knoten a (Baum a) (Baum a) deriving Show
type Suchbaum a = Baum a
g :: Ord a => (Liste a) -> (Suchbaum a)
h :: Ord a => (Baum a) -> (Liste a)
- Ergebnisse der Aufrufe in (a) und (b):
Die Angabe lautete:
- g überführt eine Liste in einen Suchbaum: ist k Knoten eines Suchbaums mit Markierung m, so sind alle Markierungen im linken Teilbaum von k echt größer als m und alle Markierungen imrechten Teilbaum von k ehct kleiner als m; ein Suchbaum ist deshalb frei von Duplikaten: keine Markierung kommt mehrfach vor
- (a):
Knoten 6 Blatt (Knoten 2 (Knoten 3 (Knoten 5 Blatt Blatt) Blatt) Blatt)(Hängt evt. von der eigenen Implementierung ab)
- (a):
Andere Meinung: es gibt zwei mögliche Reihenfolge
- man arbeitet die Liste von außen nach innen ab: Knoten 5 (Knoten 6 Blatt Blatt) (Knoten 3 Blatt (Knoten 2 Blatt Blatt) Blatt)
- man arbeitet die Liste von innen nach außen ab: Knoten 6 Blatt (Knoten 2 (Knoten 5 Blatt (Knoten 3 Blatt Blatt)) Blatt)
- (b):
E 4 (E 6 (E 11 (E 15 Ende)))
- (b):
- Warum können
gundhkomponiert werden, obwohl der Bildtyp vongund der Argumenttyp vonhnamensverschieden sind?
Suchbaum aist ein Typsynonym, d.h. es ist kein neuer Typ, sondern nur ein anderer Name fürBaum aund kann daher gleich verwendet werden. - Implementieren (a) von g und (b) von h:
- (a):
g Ende = Blatt g (E x l) = fuege_ein x (g l) fuege_ein :: Ord a => a -> (Suchbaum a) -> (Suchbaum a) fuege_ein x Blatt = Knoten x Blatt Blatt fuege_ein x (Knoten e bl br) | x < e = Knoten e bl (fuege_ein x br) | x > e = Knoten e (fuege_ein x bl) br | otherwise = Knoten e bl br
- (b):
h Blatt = Ende h (Knoten e l r) = verbinde (h r) (verbinde (E e Ende) (h l)) verbinde :: (Liste a) -> (Liste a) -> (Liste a) verbinde Ende l = l verbinde l Ende = l verbinde (E x lr) l2 = E x (verbinde lr l2)
- (a):
- Erklärung:
gerstellt aus dem letzten Listenelement einen Suchbaum, in den alle vorhergehenden Elemente eingefügt werden.
herstellt rekursiv Listen aus dem rechten Teilbaum, dem Knotenelement und dem linken Teilbaum, die dann konkateniert werden. - Genügt ... dem Hauptleitsatz funktionaler Programmierung? (Typen sollen nur so weit eingeschränkt sein, dass eine fehlerfreie Ausführung gewährleistet ist)
- (a)
Baum a
Ja, der Typahat hier keinerlei Einschränkungen. - (b)
Suchbaum a
Ja,Suchbaum aist gleichwertig zuBaum aund daher gilt dasselbe wie bei (a). - (c)
g
Ja,aist nur auf Typen der TypklasseOrdbeschränkt, was für die Erstellung des Suchbaums notwendig ist. - (d)
h
Nein,aist auf Typen der TypklasseOrdbeschränkt, obwohl das für die Funktion nicht notwendig ist. - (e)
f
Ja, daaingauf Typen der TypklasseOrdbeschränkt ist, muss das auch infgelten.
- (a)
(Pfusch)Lösung von Padraig zu den Implementierungen
f :: Ord a => (Liste a) -> (Liste a)
f = h . g
data Baum a = Blatt | Knoten a (Baum a) (Baum a) deriving Show
type Suchbaum a = Baum a
g :: Ord a => (Liste a) -> (Suchbaum a)
g l = g' l Blatt -- Baum baum = new Baum()
g' :: Ord a => (Liste a) -> (Suchbaum a) -> (Suchbaum a)
g' Ende b = b
g' (E a l) b = g' l (addNode a b)
addNode :: Ord a => a -> (Suchbaum a) -> (Suchbaum a)
addNode a Blatt = (Knoten a) Blatt Blatt
addNode a (Knoten b l r)
| a > b = Knoten b (addNode a l) r
| a < b = Knoten b l (addNode a r)
| otherwise = Knoten b l r
h :: Ord a => (Baum a) -> (Liste a)
h b = convertListe (convertList b)
convertList :: (Baum a) -> [a]
convertList (Blatt) = []
convertList (Knoten a l r) = (convertList r) ++ [a] ++ (convertList l)
convertListe :: [a] -> (Liste a)
convertListe [] = Ende
convertListe (x:xs) = (E x (convertListe xs))
Aufgabe 3 (4 + 4 + 4 = 12 Punkte)[Bearbeiten | Quelltext bearbeiten]
- Richtig. Die Entfernung von newtype-Deklarationen würde die Ausdruckskraft und Mächtigkeit von Haskell nicht ändern. Das liegt daran, dass newtype in erster Linie ein Mittel zur Verbesserung der Typsicherheit und zur Leistungsverbesserung ist, aber nicht zur Erweiterung der grundsätzlichen Ausdruckskraft der Sprache. Alles, was man mit newtype machen kann, ist auch mit data möglich (kann aber zu Overhead führen).
- Falsch, sie führen zwar zum selben Ergebnis, jedoch spielt die Ausführungsreihenfolge gerade bei Haskell eine große Rolle, weil so der Umgang mit unendlichen Strukturen ermöglicht wird.
- Falsch, seine wichtigste wissenschaftliche Leistung war das Lambda-Kalkül.
Aufgabe 4 (5 + 8 + 2 = 15 Punkte)[Bearbeiten | Quelltext bearbeiten]
- Wenn e1, e2 ineinander konvertierbar sind, d.h. e1 ←→ e2, dann gibt es einen gemeinsamen λ-Ausdruck e, zu dem e1, e2 reduziert werden k ̈onnen, d.h. e1 →∗ e und e2 →∗ e. Informell: Wenn eine Normalform existiert, dann ist sie (bis auf α-Konversion) eindeutig bestimmt!
- Wenn ein Ausdruck auf verschiedene Arten reduziert werden kann, führen alle Reduktionswege zu einem gemeinsamen Ergebnis. Die Konfluenzeigenschaft gewährleistet also die Eindeutigkeit der Auswertung von Lambda-Kalkül-Ausdrücken. Es stellt sicher, dass verschiedene Berechnungspfade zu konsistenten Ergebnissen führen und dass der Wert eines Ausdrucks unabhängig von der gewählten Reihenfolge der Reduktionsschritte ist.
- Diamant- und Rauteneigenschaft
Aufgabe 5 (12 + 6 + 4 = 22 Punkte)[Bearbeiten | Quelltext bearbeiten]
- Die Funktion könnte beispielsweise so ausschauen:
-- h ... Haendler -- m ... Markt -- a ... Artikel bb :: Haendler -> Markt -> Markt bb h m = \h' -> if h' == h then \a' -> min_preis m a' else m h' where preis h a = (m h) a min_preis m a = min (preis H1 a) (min (preis H2 a) (preis H3 a)) -- minor adjustments (Padraig) bb :: Haendler -> Markt -> Markt bb h m = \h' -> (if h' == h then WK (\a' -> min_preis m a') else m h') where preis h a = (unpack (m h)) a min_preis m a = min (preis H1 a) (min (preis H2 a) (preis H3 a)) unpack (WK fkt) = fkt
- Mithilfe des Lambda-Kalküls (Zeile 6) wird der neue Markt so zurückgegeben, dass im Falle des angegebenen Händlers ein neuer Warenkatalog zurückgegeben wird (Zeile 7), der bei jedem Artikel einen neuen minimalen Preis auswählt.
- Warenkatalog könnte auch ein newtype, oder noch besser, ein type (Synonym für die Funktion) sein: type Warenkatalog = (Artikel -> Preis)