EMZETT.
Login

Kurz: Eine Liste enthält Elemente gleichen Typs. Sie ist eine einfach verkettete Struktur (1 : 2 : 3 : []).

Teil des Kurses Haskell

Kapitel 4 von 9 im Kurs Haskell (Abschnitt „Daten verarbeiten“). Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Listen

Eine Liste enthält Elemente gleichen Typs. Sie ist eine einfach verkettete Struktur (1 : 2 : 3 : []).

main :: IO ()
main = do
  let z = [5, 3, 9, 1, 7] :: [Int]
  print (head z, last z, init z, tail z)
  print (length z, sum z, product z, maximum z, minimum z)
  print (take 2 z, drop 2 z, splitAt 2 z, reverse z)
  print (z !! 2, elem 9 z, notElem 9 z)
  print (0 : z, z ++ [11], [1, 2] ++ [3])
  print ([1 .. 5], [1, 3 .. 11], [10, 8 .. 1], ['a' .. 'e'])
  print (null z, null [])
  print (replicate 3 'x', concat [[1], [2, 3]], concatMap show [1, 2, 3])
  print (zip [1, 2, 3] "abc", unzip [(1, 'a'), (2, 'b')])
  print (zipWith (+) [1, 2, 3] [10, 20, 30])
  print (lookup 2 [(1, "eins"), (2, "zwei")])
  print (words "ein kurzer Satz", unwords ["a", "b"], lines "x\ny", unlines ["a", "b"])

Ausgabe:

(5,7,[5,3,9,1],[3,9,1,7])
(5,25,945,9,1)
([5,3],[9,1,7],([5,3],[9,1,7]),[7,1,9,3,5])
(9,True,False)
([0,5,3,9,1,7],[5,3,9,1,7,11],[1,2,3])
([1,2,3,4,5],[1,3,5,7,9,11],[10,8,6,4,2],"abcde")
(False,True)
("xxx",[1,2,3],"123")
([(1,'a'),(2,'b'),(3,'c')],([1,2],"ab"))
[11,22,33]
Just "zwei"
(["ein","kurzer","Satz"],"a b",["x","y"],"a\nb\n")

Weil Listen verkettet sind, ist head/(:) schnell, last und !! aber langsam. Für Zugriff per Index und viele Daten nutzt man Data.Vector, für Schlüssel/Wert Data.Map.

map, filter, fold

Die Bausteine der funktionalen Programmierung:

main :: IO ()
main = do
  let z = [1 .. 10] :: [Int]
  print (map (* 2) z)
  print (filter even z)
  print (foldr (+) 0 z)                        -- von rechts falten
  print (foldl (flip (:)) [] "abc")             -- von links falten
  print (foldl (\acc x -> acc * 10 + x) 0 [1, 2, 3])
  print (all even z, any (> 9) z)
  print (takeWhile (< 4) z, dropWhile (< 8) z, span even [2, 4, 5, 6], break (> 3) z)
  print (scanl (+) 0 [1, 2, 3, 4])
  print (iterate (* 2) 1 !! 10)
  print (sum (map (^ 2) (filter odd z)))
  print (length (filter (\x -> x `mod` 3 == 0) z))
  print (zip3 [1, 2] "ab" [True, False])
  print (foldr (\x acc -> if x > 3 then x : acc else acc) [] z)

Ausgabe:

[2,4,6,8,10,12,14,16,18,20]
[2,4,6,8,10]
55
"cba"
123
(False,True)
([1,2,3],[8,9,10],([2,4],[5,6]),([1,2,3],[4,5,6,7,8,9,10]))
[0,1,3,6,10]
1024
165
3
[(1,'a',True),(2,'b',False)]
[4,5,6,7,8,9,10]
FunktionZweck
map f xsf auf jedes Element anwenden
filter p xsElemente behalten, für die p wahr ist
foldr f z xs, foldl f z xszu einem Wert zusammenfassen
zip, zipWithListen paarweise verbinden
takeWhile, dropWhile, spannach Bedingung teilen

Listen-Komprehensionen

Schreibweise wie in der Mathematik: [ausdruck | generator, bedingung]

main :: IO ()
main = do
  print [x * x | x <- [1 .. 10]]
  print [x | x <- [1 .. 20], x `mod` 3 == 0]
  print [(x, y) | x <- [1 .. 3], y <- "ab"]
  print [(a, b, c) | c <- [1 .. 20], b <- [1 .. c], a <- [1 .. b], a * a + b * b == c * c]
  print [if even x then "gerade" else "ungerade" | x <- [1 .. 4]]
  print [c | c <- "Haskell Programmierung", c `elem` "aeiou"]
  print (sum [1 / fromIntegral (n * n) | n <- [1 .. 1000 :: Int]] :: Double)
  let teiler n = [d | d <- [1 .. n], n `mod` d == 0]
  print (teiler 28, sum (init (teiler 28)) == 28)
  print [x | Just x <- [Just 1, Nothing, Just 3]]

Ausgabe:

[1,4,9,16,25,36,49,64,81,100]
[3,6,9,12,15,18]
[(1,'a'),(1,'b'),(2,'a'),(2,'b'),(3,'a'),(3,'b')]
[(3,4,5),(6,8,10),(5,12,13),(9,12,15),(8,15,17),(12,16,20)]
["ungerade","gerade","ungerade","gerade"]
"aeoaieu"
1.6439345666815615
([1,2,4,7,14,28],True)
[1,3]

Sortieren und Data.List

import Data.Char (toUpper, isDigit, ord, chr, isAlpha)
import Data.List (sort, sortBy, sortOn, nub, group, partition, isPrefixOf, isSuffixOf, isInfixOf, intercalate, transpose, foldl', tails, subsequences, permutations)
import Data.Ord (comparing, Down (..))
 
main :: IO ()
main = do
  print (sort [3, 1, 2], sortBy (comparing negate) [3, 1, 2], sortOn Down [3, 1, 2])
  print (sortOn snd [(1, 'c'), (2, 'a'), (3, 'b')])
  print (nub [1, 2, 1, 3, 2])
  print (map (\g -> (head g, length g)) (group (sort "mississippi")))
  print (partition even [1 .. 8])
  print ("Has" `isPrefixOf` "Haskell", "ell" `isSuffixOf` "Haskell", "ske" `isInfixOf` "Haskell")
  print (intercalate ", " ["a", "b", "c"], transpose [[1, 2, 3], [4, 5, 6]])
  print (foldl' (+) 0 [1 .. 100000])
  print (map toUpper "hallo", filter isDigit "a1b22", ord 'A', chr 98)
  print (take 3 (tails [1, 2, 3]), length (subsequences [1 .. 4]), length (permutations [1 .. 4]))
  print (zip "abc" [1 ..])
  print (maximum (map length (words "ein kleiner langer Satz")))

Ausgabe:

([1,2,3],[3,2,1],[3,2,1])
[(2,'a'),(3,'b'),(1,'c')]
[1,2,3]
[('i',4),('m',1),('p',2),('s',4)]
([2,4,6,8],[1,3,5,7])
(True,True,True)
("a, b, c",[[1,4],[2,5],[3,6]])
5000050000
("HALLO","122",65,'b')
([[1,2,3],[2,3],[3]],16,24)
[('a',1),('b',2),('c',3)]
7

Merke

  • Listen: head, tail, take, drop, ++, :, !!, zip, length
  • Kern der funktionalen Programmierung: map, filter, foldr/foldl
  • Listen-Komprehensionen: [ausdruck | x <- liste, bedingung]
  • Data.List und Data.Char bieten sort, nub, group, isPrefixOf, toUpper …
  • Bei großen Daten: foldl' (streng), Data.Map, Data.Vector

Übungsaufgabe

Zähle mit group und sort, wie oft jedes Wort in einem Satz vorkommt.

Quiz zur Selbstkontrolle

?

  • Summiert die Liste zu 6 (richtig)
  • Liefert [1,2,3]
  • Multipliziert alle
  • Dreht die Liste um

?

  • Alle geraden Elemente von xs (richtig)
  • Die Summe
  • Das erste Element
  • Die Länge

"ab"?

  • [(1,‘a’),(2,‘b’)] (richtig)
  • [(1,‘a’),(2,‘b’),(3,”)]
  • Einen Fehler
  • [1,2,3,‘a’,‘b’]

Weiter im Kurs

Zurück: Pattern Matching, Guards und Rekursion

Weiter: Eigene Typen und Typklassen

Alle Kapitel: Haskell im Überblick