cleanup at GZI
This commit is contained in:
parent
352b1be3f2
commit
ae9eade752
@ -1,90 +1,116 @@
|
|||||||
# Übungsblatt 1
|
-- Übungsblatt 1
|
||||||
|
-- =============
|
||||||
|
--
|
||||||
|
-- Typtheorie
|
||||||
|
-- ----------
|
||||||
|
--
|
||||||
|
-- Schreiben Sie alle **möglichen** Implementationen der folgenden
|
||||||
|
-- Funktionen. Wozu könnte `fun2` nützlich sein?
|
||||||
|
|
||||||
## Typtheorie
|
|
||||||
|
|
||||||
Schreiben Sie alle **möglichen** Implementationen der folgenden Funktionen. Wozu könnte `fun2` nützlich sein?
|
|
||||||
|
|
||||||
```haskell
|
|
||||||
fun1 :: a -> a
|
fun1 :: a -> a
|
||||||
fun1 = _fun1
|
fun1 a = a
|
||||||
|
|
||||||
|
-- id
|
||||||
|
|
||||||
fun2 :: a -> b -> a
|
fun2 :: a -> b -> a
|
||||||
fun2 = _fun2
|
fun2 a _ = a
|
||||||
|
|
||||||
fun3 :: (Eq a) => a -> a -> Bool
|
fun3 :: (Eq a) => a -> a -> Bool
|
||||||
fun3 = _fun3
|
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.
|
-- Wir haben in der Vorlesung parametrisierte Typen kennengelernt. Der
|
||||||
|
-- simpelste hiervon ist `Identity`, der nur einen anderen Typen einpackt.
|
||||||
|
|
||||||
```haskell
|
|
||||||
data Identity a = Identity a
|
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
|
-- Diese Definition stellt uns automatisch den Konstruktor
|
||||||
|
-- `Identity :: a -> Identity a` zur Verfügung, der ein `a` einpackt.
|
||||||
|
-- Schreiben Sie die Funktion
|
||||||
|
|
||||||
```haskell
|
|
||||||
unIdentity :: Identity a -> a
|
unIdentity :: Identity a -> a
|
||||||
unIdentity = _unIdentity
|
unIdentity (Identity a) = a
|
||||||
```
|
|
||||||
|
|
||||||
welche diesen Vorgang wieder rückgängig macht.
|
-- 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
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
```haskell
|
|
||||||
mapIdentity :: (a -> b) -> Identity a -> Identity b
|
mapIdentity :: (a -> b) -> Identity a -> Identity b
|
||||||
mapIdentity = _mapIdentity
|
mapIdentity f a = Identity . f . unIdentity
|
||||||
```
|
|
||||||
|
|
||||||
**Hinweis:** Es gibt *zwei* prinzipielle Vorgehen dieses zu implementieren. Kommen Sie auf beide?
|
--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
|
||||||
|
|
||||||
## Funktionen sind auch nur Typen
|
|
||||||
|
|
||||||
Datentypen können auch Funktionen enthalten. Sehen Sie sich einmal den Datentypen
|
|
||||||
|
|
||||||
```haskell
|
|
||||||
data Pred a = Pred (a -> Bool)
|
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).
|
-- 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
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
```haskell
|
-- Da Haskell-Funktionen aber "gecurried" sind (mehr dazu in der
|
||||||
unPred :: Pred a -> (a -> Bool)
|
-- Vorlesung), können Sie die Klammern hinten in der Signatur auch
|
||||||
unPred = _unPred
|
-- 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?
|
||||||
|
|
||||||
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?
|
|
||||||
|
|
||||||
```haskell
|
|
||||||
mapPred :: _fun -> Pred a -> Pred b
|
mapPred :: _fun -> Pred a -> Pred b
|
||||||
mapPred = _mapPred
|
mapPred f (Pred a) = _mapPred
|
||||||
```
|
|
||||||
|
|
||||||
## Neue Typen erfinden
|
-- 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.
|
||||||
|
|
||||||
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.
|
data Vielleicht a = Exercise
|
||||||
|
|
||||||
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.
|
-- 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
|
||||||
|
|
||||||
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
|
|
||||||
```haskell
|
|
||||||
mapVielleicht :: (a -> b) -> Vielleicht a -> Vielleicht b
|
mapVielleicht :: (a -> b) -> Vielleicht a -> Vielleicht b
|
||||||
mapVielleicht = _mapVielleicht
|
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?
|
|
||||||
|
|
||||||
|
|
||||||
|
-- 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?
|
||||||
|
128
Übungen/Blatt1.solution.hs
Normal file
128
Übungen/Blatt1.solution.hs
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
-- Ü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 = 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 :: (b -> a) -> Pred a -> Pred b
|
||||||
|
mapPred f (Pred a) = Pred (a . f)
|
||||||
|
|
||||||
|
-- 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 = Etwas a
|
||||||
|
| Nichts
|
||||||
|
|
||||||
|
-- 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 f (Etwas a) = Etwas (f a)
|
||||||
|
mapVielleicht f Nichts = Nichts
|
||||||
|
|
||||||
|
-- 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?
|
||||||
|
|
||||||
|
fun4 :: Pred (Vielleicht a) -> x
|
||||||
|
fun4 (Pred a) = undefined
|
||||||
|
|
||||||
|
fun5 :: Vielleicht (Pred a) -> x
|
||||||
|
fun5 (Etwas (Pred a)) = undefined
|
||||||
|
fun5 Nichts = undefined
|
||||||
|
|
||||||
|
|
||||||
|
main = putStrLn "compiles"
|
Loading…
Reference in New Issue
Block a user