Vorlesung2016/Übungen/Blatt1.md

3.8 KiB

-- Übungsblatt 1 -- =============

-- Typtheorie


-- -- Schreiben Sie alle möglichen Implementationen der folgenden -- Funktionen. Wozu könnte fun2 nützlich sein?

fun1 :: a -> a fun1 a = a

-- id

fun2 :: a -> b -> a fun2 a _ = a

fun3 :: (Eq a) => a -> a -> Bool fun3 _ _ = True fun3 _ _ = False fun3 = (==) fun3 = (/=)

-- Wir haben in der Vorlesung parametrisierte Typen kennengelernt. Der -- simpelste hiervon ist Identity, der nur einen anderen Typen einpackt.

data Identity a = Identity a

-- Diese Definition stellt uns automatisch den Konstruktor -- Identity :: a -> Identity a zur Verfügung, der ein a einpackt. -- Schreiben Sie die Funktion

unIdentity :: Identity a -> a unIdentity (Identity a) = a

-- welche diesen Vorgang wieder rückgängig macht.

-- Angenommen, Sie hätten nun ein Wert vom Typen Identity a und eine -- Funktion mit dem Typen a -> b. Wie wenden Sie diese auf das a -- "innerhalb" des Identity an um ein Identity b herzustellen? -- Schreiben Sie also eine Funktion

mapIdentity :: (a -> b) -> Identity a -> Identity b mapIdentity f a = Identity . f . unIdentity

--mapIdentity f (Identity a) = Identity (f a)

-- Hinweis: Es gibt zwei prinzipielle Vorgehen dieses zu -- implementieren. Kommen Sie auf beide?

-- Funktionen sind auch nur Typen


-- -- Datentypen können auch Funktionen enthalten. Sehen Sie sich einmal den -- Datentypen

data Pred a = Pred (a -> Bool)

-- an. Hier wird ein Prädikat definiert, welches (gegeben einen Datentyp -- a) eine Funktion gespeichert hat, die a in einen Bool umwandeln -- kann (etwa um irgendwas zu filtern/selektieren/löschen/..., wenn man -- dies an eine weitere Funktion übergibt).

-- Auch hier können Sie eine Funktion schreiben, die das Pred a wieder -- "auspackt". Definieren Sie

unPred :: Pred a -> a -> Bool unPred (Pred a) = a

-- Da Haskell-Funktionen aber "gecurried" sind (mehr dazu in der -- Vorlesung), können Sie die Klammern hinten in der Signatur auch -- weglassen und erhalten unPred :: Pred a -> a -> Bool, was man zugleich -- als "wende Pred a an, wenn du ein a bekommst" lesen kann. In der Tat -- sind beide Funktionen identisch (wieso?).

-- Bonus

-- Was für eine Funktion bräuchten Sie um ein Pred a in ein Pred b -- umzuwandeln? Können Sie diese implementieren?

mapPred :: _fun -> Pred a -> Pred b mapPred f (Pred a) = _mapPred

-- Neue Typen erfinden


-- -- In Haskell ist ein zentraler Vorgehenspunkt das Definieren und Verwenden -- von eigenen Datentypen. Zur Erinnerung; es gibt zwei Möglichkeiten, die -- man miteinander kombinieren kann: data Prod a b c = Prod a b c -- (Produkttyp) benötigt sowohl a, b als auch c um einen Wert zu -- erzeugen, data Sum a b = Sum1 a | Sum2 b (Summentyp) braucht entweder -- ein a um durch den Konstruktor Sum1 ein Sum a b zu erzeugen oder -- ein b um durch den Konstruktor Sum2 ein Sum a b zu erzeugen.

-- Definieren Sie einen Datentypen Vielleicht a, der zwei Konstruktoren -- besitzt: Einen Konstruktor, mit dem durch ein a ein Vielleicht a -- konstruiert wird und ein zweiter Konstruktor, der keinen Wert nimmt, -- sondern die "Abwesenheit eines a" symbolisieren soll.

data Vielleicht a = Exercise

-- Können Sie hier eine Funktion schreiben, die das a extrahiert? Wenn -- ja, implementieren Sie diese; wenn nein, geben Sie eine kurze -- Begründung.

-- Wie würden Sie mittels einer Funktion a -> b ein Vielleicht a in ein -- Vielleicht b wandeln? Implementieren Sie

mapVielleicht :: (a -> b) -> Vielleicht a -> Vielleicht b mapVielleicht = _mapVielleicht

-- Bonus

-- Man kann Typen natürlich auch Schachteln. Worin liegt eigentlich der -- Unterschied zwischen einem Pred (Vielleicht a) und einem -- Vielleicht (Pred a)? Oder sind diese identisch?