Organisatorisches

Tutorium 5 und 7

Übungsblätter

  • Kein Übungsschein
  • Trotzdem: Bitte unbedingt Übungsblätter machen!
  • Besprechung der Lösung im darauffolgenden Tutorium

Klausur (Informatik)

  • 120 Minuten
  • 24.03.2020 um 11 Uhr
  • Beliebige Papier-Materialien erlaubt
    • Vorlesungsfolien
    • Musterlösungen
    • Bücher
    • Dokus
    • ...

Haskell ist anders...

  • (Fast) alles Funktionen
    • Abbildung von Eingabe im Definitionsbereich...
    • ...auf Ausgabe im Wertebereich
    • Keine Seiteneffekte
    • Weniger "Wie?", mehr "Was?"
  • Keine Variablen
  • Typisiert (Typinferenz)
In [1]:
f x = cos x / 2
f pi
-0.5

Funktionsdefinition

myfunction x y z = <Ausdruck>
g x = sin x
f x y = (x / sin x) * g y
In [2]:
g x = sin x
f x y = (x / sin x) * g y
Eta reduce
Found:
g x = sin x
Why Not:
g = sin

Funktionsaufruf

  • myfunction x y
  • Linksassoziativ
In [3]:
f 2 2 -- Rufe f mit Parametern 2 und 2 auf
g (f 2 2) -- Rufe g mit Ergebnis von (f 2 2) als Parameter auf
2.0
0.9092974268256817

$\lambda$-Ausdrücke

Statt

f x = <Ausdruck>

kann man auch schreiben:

f = \x -> <Ausdruck>

Funktionen höherer Ordnung

Funktionen können auch Funktionen als Ein- oder Ausgabe haben

In [4]:
callWithPlus5 f = \x -> f (x+5)
invertNum x = -x

invertNum (-3)
(callWithPlus5 invertNum) (-3)
Redundant lambda
Found:
callWithPlus5 f = \ x -> f (x + 5)
Why Not:
callWithPlus5 f x = f (x + 5)
Redundant bracket
Found:
(callWithPlus5 invertNum) (-3)
Why Not:
callWithPlus5 invertNum (-3)
3
-2

Eingabe der Funktion callWithPlus5: Funktion die Integer entgegennimmt
Ausgabe der Funktion callWithPlus5: Funktion die Integer entgegennimmt

Eingebaute Typen

  • Int
    
  • Bool
    
  • Float
    
  • Char
    
  • [1,2,3]
    
  • (1,2)
    

Eingebaute Funktionen

Für Int und Float

  • (+)
  • (-)
  • (*)
  • (^) (zweites Argument muss Int sein)
  • (<)
  • (<=)
  • (>)
  • (>=)

Ansonsten

  • Für Int: div und mod
  • Für Float: (/)
  • Für Bool: (&&) und (||)

Typnotation

  • Jede Funktion in Haskell hat einen Typ
  • Nicht explizit, sondern durch Typinferenz
  • Nützlich bei Compiler Ausgaben
  • Rechtsassoziativ
In [5]:
h x y = x + y + 2
:t h
h :: forall a. Num a => a -> a -> a

Hier relevant:

a -> a -> a

bzw.:

a -> (a -> a)

Parameter 1: Typ a
Parameter 2: Typ a
Ausgabe: Typ a
Zusätzlich bedeutet Num a, dass a die Typklasse Num hat.
Details dazu später

Was bedeutet also?

In [6]:
:t (||)
(||) :: Bool -> Bool -> Bool

Abbildung von zwei Bool Eingaben auf eine Bool Ausgabe

Wie schreiben wir...

...eine Funktion die als Eingabe nimmt:

  1. Ein Integer
  2. Ein Bool
  3. Eine Liste von Char und deren Ausgabe ein Float ist

Wie schreiben wir...

...eine Funktion die als Eingabe eine Funktion vom Typ Integer -> Bool nimmt und eine Funktion vom Typ Bool->Integer ausgibt?

Scoping

Nervig:

In [7]:
add5 x = x + 5
add10 x = add5 (add5 x)
add10 10
20

add5 wird nur als Subroutine von add10 verwendet.
Besser:

In [8]:
add10' x = add5' (add5' x)
    where add5' z = z + 5
add10' 10
20

Fallunterscheidung

1. If Then Else

In [9]:
absoluteVal0 x = if x>=0 then x else -x
absoluteVal0 (-10)
10

2. Pattern-Matching

In [10]:
condInvert True a = -a
condInvert False a = a
condInvert True 10
condInvert False 10
-10
10

3. Gates

In [11]:
absoluteVal1 x
    | x >= 0 = x
    | otherwise = -x
absoluteVal1 (-10)
10

...and errors

In [12]:
absoluteVal1 x
    | x > 0 = x
    | x == 0 = error "For some (unknown) reason this is supposed to be impossible for 0"
    | otherwise = -x
absoluteVal1 0
For some (unknown) reason this is supposed to be impossible for 0
CallStack (from HasCallStack):
  error, called at <interactive>:3:16 in interactive:Ghci386

Rekursion

Klassisches Beispiel: Fakultät

In [13]:
fak 0 = 1
fak n = n * fak (n-1)

fak 6
720

Endrekursion

  • Linear Rekursiv
    In jedem Definitionszweig nur ein rekursiver Aufruf
  • Endrekursion
    Wenn in jedem Zweig der rekursive Aufruf nicht in andere Aufrufe eingebettet

Warum Endrekursion?

In [14]:
-- Aufgabe 1: Endrekursive Version von `fak` (2 min)
fak' n = fakAcc n 1
    where fakAcc n acc
            | n == 0 = acc
            | otherwise = fakAcc (n-1) (n*acc)

fak' 5
120
In [15]:
-- Aufgabe 2: Endrekursion für Fibbonaci Zahlen (5 min)
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
fib' n = fibAcc n 0 1
    where fibAcc n a b
            | n==0 = a
            | otherwise = fibAcc (n-1) b (a+b)
fib 30
fib' 30
832040
832040

Listen

Eine Liste ist entweder...

  • ...leer []
  • ... ein Konstrukt (x:xs) aus einem Listenkopf x und einer Restliste xs
In [16]:
-- Gib alle Zahlen kleiner gleich n als Liste zurück
mylist 0 = []
mylist n = n : mylist (n-1)
mylist 5
[5,4,3,2,1]
In [17]:
-- Aufgabe 3: Schreibe eine Funktion, die alle geraden Zahlen < n zurückgibt (3min)
evennumbers n acc
    | n == 0 = acc ++ [0]
    | n `mod` 2 == 0 = evennumbers (n-2) (acc ++ [n])
    | n `mod` 2 == 1 = evennumbers (n-1) acc
    
evennumbers' n = tail (evennumbers'' n)
    where evennumbers'' n
            | n == 0 = [0]
            | even n = n : (evennumbers'' (n-2))
            | otherwise = evennumbers'' (n-1)

evennumbers' 10
Redundant bracket
Found:
n : (evennumbers'' (n - 2))
Why Not:
n : evennumbers'' (n - 2)
[8,6,4,2,0]

Eingebaute Listenfunktionen

  • (++) Konkatenation
  • (!!) Indexzugriff
  • head, last Erstes bzw. letztes Element
  • null ist Liste leer?
  • take / drop Die ersten n Elemente nehmen/auslassen
  • length Länge der Liste
  • reverse Dreht die Liste um
  • elem x l Testet, ob x in der Liste enthalten ist

Listen: Fun Facts

Fallunterscheidung

Beispiel Listenlänge:

length [] = 0
length (x:xs) = 1 + length xs

Strings

...sind eigentlich nur Listen von Chars

In [18]:
head "Text"
tail "Text"
'T'
"ext"

Module

  • Zur Abgabe der Übungsblätter
  • Dateiname: <Name>.hs
  • Dateinhalt:
    module <Name> where
    ...
    
  • Name erhaltet ihr in Aufgabenstellung

Haskell in der Klausur

  • Alles in der Prelude
  • Alles auf den Folien
  • Wenn aus Übungsblatt oder alter Klausur: Dann schreiben woher es kommt (sehr unwahrscheinlich, dass notwendig!)

Übungsblatt 0

Probleme? Fragen?

In [19]:
max3if x y z = if x >= y
    then if x >= z then x else z
    else if y >= z then y else z

max3guard x y z
    | x >= y && x >= z = x
    | y >= x && y >= z = y
    | otherwise = z

max3max x y z = max x (max y z)

max3if 3 4 5
max3guard 3 4 5
max3max 3 4 5
Use guards
Found:
max3if x y z = if x >= y then if x >= z then x else z else if y >= z then y else z
Why Not:
max3if x y z | x >= y = if x >= z then x else z | y >= z = y | otherwise = z
5
5
5

Weitere Übungen...

In [21]:
-- Aufgabe 4 (10 min) baut die Listenfunktionen nach
concat' [] l2 = l2
concat' (x:xs) l2 = x : (concat' xs l2)

indexAccess 0 (x:xs) = x
indexAccess n [] = error "out of bounds"
indexAccess n (x:xs) = indexAccess (n-1) xs

head' [] = error "empty"
head' (x:xs) = x
last' [] = error "empty"
last' [x] = x
last' (x:xs) = last' xs

null' [] = True
null' l = False

take' 0 l = []
take' n [] = [] -- alternativ: error ""
take' n (x:xs) = x : take' (n-1) xs
drop' 0 l = l
drop' n [] = [] -- alternativ: error ""
drop' n (x:xs) = drop' (n-1) xs

reverse' l =  reverseAcc l []
    where 
            reverseAcc [] acc = acc
            reverseAcc (x:xs) acc = reverseAcc xs (x:acc)

elem' x [] = False
elem' x (y:ys) = if x == y then True else elem' x ys

mytestlist = [0,1,2,3,4,5,6,7,8,9]
concat' [-2,-1] mytestlist
indexAccess 4 mytestlist
head' mytestlist
last' mytestlist
null' mytestlist
null' []
take' 3 mytestlist
drop' 3 mytestlist
reverse' mytestlist
elem' 3 mytestlist
elem' 10 mytestlist
Use foldr
Found:
concat' [] l2 = l2 concat' (x : xs) l2 = x : (concat' xs l2)
Why Not:
concat' xs l2 = foldr (:) l2 xs
Redundant bracket
Found:
x : (concat' xs l2)
Why Not:
x : concat' xs l2
Use foldl
Found:
reverseAcc [] acc = acc reverseAcc (x : xs) acc = reverseAcc xs (x : acc)
Why Not:
reverseAcc xs acc = foldl (flip (:)) acc xs
Redundant if
Found:
if x == y then True else elem' x ys
Why Not:
(x == y) || elem' x ys
[-2,-1,0,1,2,3,4,5,6,7,8,9]
4
0
9
False
True
[0,1,2]
[3,4,5,6,7,8,9]
[9,8,7,6,5,4,3,2,1,0]
True
False
In [ ]: