EMZETT.
Login

Kurz: Funktionen werden durch Muster definiert; die erste passende Zeile gewinnt:

Teil des Kurses Haskell

Kapitel 3 von 9 im Kurs Haskell. Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Pattern Matching

Funktionen werden durch Muster definiert; die erste passende Zeile gewinnt:

beschreibe :: Int -> String
beschreibe 0 = "null"
beschreibe 1 = "eins"
beschreibe n
  | n < 0 = "negativ"
  | even n = "gerade"
  | otherwise = "ungerade"
 
erstes :: [a] -> Maybe a
erstes [] = Nothing
erstes (x : _) = Just x
 
laenge :: [a] -> Int
laenge [] = 0
laenge (_ : rest) = 1 + laenge rest
 
summe :: [Int] -> Int
summe [] = 0
summe (x : xs) = x + summe xs
 
tuplePlus :: (Int, Int) -> Int
tuplePlus (a, b) = a + b
 
main :: IO ()
main = do
  mapM_ (putStrLn . beschreibe) [0, 1, -5, 4, 7]
  print (erstes [10, 20], erstes ([] :: [Int]))
  print (laenge "Haskell", summe [1 .. 100], tuplePlus (3, 4))
  let liste@(kopf : _) = [5, 6, 7]       -- as-Muster: ganze Liste und Kopf
  print (kopf, length liste)

Ausgabe:

null
eins
negativ
gerade
ungerade
(Just 10,Nothing)
(7,5050,7)
(5,3)
  • _ ignoriert einen Wert
  • (x : xs) zerlegt eine Liste in Kopf und Rest
  • name@muster bindet das Ganze und zerlegt es zugleich

Guards, if, case, let, where

bmi :: Double -> Double -> String
bmi gewicht groesse
  | wert < 18.5 = "Untergewicht"
  | wert < 25 = "Normalgewicht"
  | wert < 30 = "Übergewicht"
  | otherwise = "Adipositas"
  where
    wert = gewicht / groesse ^ 2
 
wochentag :: Int -> String
wochentag n = case n of
  1 -> "Montag"
  2 -> "Dienstag"
  _ | n `elem` [6, 7] -> "Wochenende"
    | otherwise -> "anderer Tag"
 
kreis :: Double -> (Double, Double)
kreis r = (flaeche, umfang)
  where
    flaeche = pi * r ^ 2
    umfang = 2 * pi * r
 
abstand :: (Double, Double) -> (Double, Double) -> Double
abstand (x1, y1) (x2, y2) =
  let dx = x2 - x1
      dy = y2 - y1
   in sqrt (dx * dx + dy * dy)
 
main :: IO ()
main = do
  putStrLn (bmi 70 1.75)
  print (map wochentag [1, 2, 6, 3])
  print (kreis 1)
  print (abstand (0, 0) (3, 4))
  print (if 10 > 5 then "größer" else "kleiner")

Ausgabe:

Normalgewicht
["Montag","Dienstag","Wochenende","anderer Tag"]
(3.141592653589793,6.283185307179586)
5.0
"gr\246\223er"

where gehört zur Funktion und sieht deren Argumente, let ... in ... ist ein Ausdruck. otherwise ist einfach True.

Rekursion statt Schleifen

Da es keine veränderlichen Variablen gibt, wiederholt man mit Rekursion:

fib :: Int -> Integer
fib n = go n 0 1
  where
    go 0 a _ = a
    go k a b = go (k - 1) b (a + b)       -- Akkumulator: Endrekursion
 
ggT :: Int -> Int -> Int
ggT a 0 = a
ggT a b = ggT b (a `mod` b)
 
potenz :: Integer -> Int -> Integer
potenz _ 0 = 1
potenz b e
  | even e = let h = potenz b (e `div` 2) in h * h
  | otherwise = b * potenz b (e - 1)
 
collatz :: Int -> [Int]
collatz 1 = [1]
collatz n
  | even n = n : collatz (n `div` 2)
  | otherwise = n : collatz (3 * n + 1)
 
hanoi :: Int -> String -> String -> String -> [(String, String)]
hanoi 0 _ _ _ = []
hanoi n von nach hilfe = hanoi (n - 1) von hilfe nach ++ [(von, nach)] ++ hanoi (n - 1) hilfe nach von
 
main :: IO ()
main = do
  print (map fib [0 .. 10])
  print (fib 90)
  print (ggT 48 18)
  print (potenz 2 100)
  print (collatz 6)
  print (length (hanoi 10 "A" "C" "B"))
  print (hanoi 2 "A" "C" "B")

Ausgabe:

[0,1,1,2,3,5,8,13,21,34,55]
2880067194370816120
6
1267650600228229401496703205376
[6,3,10,5,16,8,4,2,1]
1023
[("A","B"),("A","C"),("B","C")]

Lazy Evaluation

Haskell berechnet Werte erst, wenn sie gebraucht werden. Dadurch sind unendliche Listen möglich:

naturalZahlen :: [Integer]
naturalZahlen = [1 ..]
 
fibs :: [Integer]
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
 
primzahlen :: [Int]
primzahlen = sieb [2 ..]
  where sieb (p : xs) = p : sieb [x | x <- xs, x `mod` p /= 0]
 
main :: IO ()
main = do
  print (take 5 naturalZahlen)
  print (take 12 fibs)
  print (takeWhile (< 40) primzahlen)
  print (fst (1, undefined))               -- undefined wird nie ausgewertet
  print (take 3 (cycle "ab"), take 3 (repeat 'x'), take 4 (iterate (* 2) 1))
  print (head (filter ((> 1000) . (^ 2)) [1 ..]))

Ausgabe:

[1,2,3,4,5]
[0,1,1,2,3,5,8,13,21,34,55,89]
[2,3,5,7,11,13,17,19,23,29,31,37]
1
("aba","xxx",[1,2,4,8])
32

Merke

  • Pattern Matching auf Werte, Tupel, Listen (x : xs); _ ignoriert
  • Guards (| bedingung), where, let ... in, case ... of, if ... then ... else
  • Rekursion mit Akkumulatoren (Endrekursion) ersetzt Schleifen
  • Lazy Evaluation erlaubt unendliche Datenstrukturen

Übungsaufgabe

Schreibe anzahlVorkommen :: Eq a => a -> [a] -> Int rekursiv.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Typen und Funktionen

Weiter: Listen und Funktionen höherer Ordnung

Alle Kapitel: Haskell im Überblick