EMZETT.
Login

Kurz: main :: IO () main = do print (sort [3, 1, 2], nub [1, 1, 2]) print (Map.toList (Map.fromList [(2, “b”), (1, “a”)])) print (toUpper ‘a’, isAlpha ‘1’) `output ([1,2,3],[1,2]) [(1,"a"),(2,"b")] ('A',False)

Teil des Kurses Haskell

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

Module importieren

import Data.List (sort, nub)                 -- nur bestimmte Namen
import qualified Data.Map as Map              -- mit Präfix: Map.insert
import Data.Char                              -- alles
import Prelude hiding (lookup)               -- Namen verbergen
 
main :: IO ()
main = do
  print (sort [3, 1, 2], nub [1, 1, 2])
  print (Map.toList (Map.fromList [(2, "b"), (1, "a")]))
  print (toUpper 'a', isAlpha '1')

Ausgabe:

([1,2,3],[1,2])
[(1,"a"),(2,"b")]
('A',False)

Die meisten Standardbibliotheken stehen im Paket base, containers (Map, Set, Seq), text, bytestring, mtl, time, random, aeson (JSON), vector.

Data.Map: Schlüssel/Wert

import qualified Data.Map.Strict as Map
import Data.Maybe (fromMaybe)
 
main :: IO ()
main = do
  let m = Map.fromList [("Mia", 17), ("Tom", 25), ("Zoe", 31)]
  print m
  print (Map.lookup "Tom" m, Map.lookup "Ben" m, Map.member "Zoe" m)
  print (Map.findWithDefault 0 "Ben" m)
  let m2 = Map.insert "Ben" 9 (Map.delete "Tom" m)
  print (Map.toList m2)
  print (Map.keys m2, Map.elems m2, Map.size m2)
  print (Map.map (+ 1) m2)
  print (Map.filter (> 10) m2)
  print (Map.insertWith (+) "Mia" 100 m2 Map.! "Mia")
  print (Map.foldr (+) 0 m2)
  print (Map.adjust (* 2) "Ben" m2)
  print (Map.alter (fmap (+ 1)) "Zoe" m2)
  let zaehle = foldr (\c -> Map.insertWith (+) c (1 :: Int)) Map.empty "mississippi"
  print (Map.toList zaehle)
  print (Map.unionWith (+) (Map.fromList [(1, 1), (2, 2)]) (Map.fromList [(2, 10), (3, 3)]))
  print (fst <$> Map.lookupMin zaehle, fst <$> Map.lookupMax zaehle)
  print (Map.toAscList (Map.fromListWith (++) [(length w, [w]) | w <- words "ein kleiner langer Satz mit drei"]))

Ausgabe:

fromList [("Mia",17),("Tom",25),("Zoe",31)]
(Just 25,Nothing,True)
0
[("Ben",9),("Mia",17),("Zoe",31)]
(["Ben","Mia","Zoe"],[9,17,31],3)
fromList [("Ben",10),("Mia",18),("Zoe",32)]
fromList [("Mia",17),("Zoe",31)]
117
57
fromList [("Ben",18),("Mia",17),("Zoe",31)]
fromList [("Ben",9),("Mia",17),("Zoe",32)]
[('i',4),('m',1),('p',2),('s',4)]
fromList [(1,1),(2,12),(3,3)]
(Just 'i',Just 's')
[(3,["mit","ein"]),(4,["drei","Satz"]),(6,["langer"]),(7,["kleiner"])]

Eine Map ist ein ausgewogener Suchbaum (Zugriff in O(log n)), immer sortiert nach Schlüssel und unveränderlich: insert liefert eine neue Map. Für Hash-basierte Varianten: Data.HashMap (Paket unordered-containers).

Data.Set und Data.Sequence

import qualified Data.Set as Set
import qualified Data.Sequence as Seq
import Data.Foldable (toList)
 
main :: IO ()
main = do
  let a = Set.fromList [1, 2, 3, 3, 2]
      b = Set.fromList [3, 4, 5]
  print (a, Set.size a, Set.member 2 a)
  print (Set.union a b, Set.intersection a b, Set.difference a b)
  print (Set.toList (Set.map (* 2) a), Set.isSubsetOf (Set.fromList [1, 2]) a)
  let q = Seq.fromList [1, 2, 3]
  print (toList (q Seq.|> 4), toList (0 Seq.<| q), Seq.length q, Seq.index q 1)
  print (toList (Seq.update 1 99 q), toList (Seq.reverse q))

Ausgabe:

(fromList [1,2,3],3,True)
(fromList [1,2,3,4,5],fromList [3],fromList [1,2])
([2,4,6],True)
([1,2,3,4],[0,1,2,3],3,2)
([1,99,3],[3,2,1])

Data.Text: effizienter Text

String ist eine Liste von Zeichen: bequem, aber langsam und speicherhungrig. Für echte Textverarbeitung nimmt man Text:

{-# LANGUAGE OverloadedStrings #-}
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
 
main :: IO ()
main = do
  let t = "  Hallo Haskell  " :: T.Text
  TIO.putStrLn (T.strip t)
  print (T.length t, T.toUpper (T.strip t))
  print (T.splitOn "," "a,b,,c")
  print (T.words "ein kurzer Satz", T.unwords ["x", "y"])
  print (T.replace "l" "L" "Hallo")
  print (T.isPrefixOf "Ha" "Haskell", T.isInfixOf "ske" "Haskell")
  print (T.intercalate "-" ["a", "b", "c"])
  print (T.pack (show 42), T.unpack "text")
  print (T.take 3 "Haskell", T.drop 3 "Haskell", T.reverse "abc")
  print (read (T.unpack "17") + (1 :: Int))

Ausgabe:

Hallo Haskell
(17,"HALLO HASKELL")
["a","b","","c"]
(["ein","kurzer","Satz"],"x y")
"HaLLo"
(True,True)
"a-b-c"
("42","text")
("Has","kell","cba")
18

OverloadedStrings lässt String-Literale als Text zu.

Eigene Module

Ein Modul steht in einer eigenen Datei (src/Geometrie.hs) und legt fest, was es exportiert:

module Geometrie
  ( Form (..)      -- Typ mit allen Konstruktoren
  , flaeche
  , umfang
  ) where
 
data Form = Kreis Double | Quadrat Double
 
flaeche :: Form -> Double
flaeche (Kreis r) = pi * r * r
flaeche (Quadrat a) = a * a
 
umfang :: Form -> Double
umfang (Kreis r) = 2 * pi * r
umfang (Quadrat a) = 4 * a
 
hilfsfunktion :: Int -> Int   -- nicht exportiert (privat)
hilfsfunktion = (+ 1)
-- Main.hs
import Geometrie
main = print (flaeche (Kreis 1))

Merke

  • import qualified Data.Map as Map verhindert Namenskonflikte
  • Data.Map/Data.Set sind unveränderliche, sortierte Bäume
  • Data.Text statt String für Text
  • Pakete: containers, text, mtl, aeson, vector
  • Module exportieren mit module Name (…) where

Übungsaufgabe

Zähle Wörter eines Textes mit Map.insertWith und gib die zehn häufigsten aus.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: IO, do-Notation und Zustand

Weiter: Werkzeuge, Projekte und Spickzettel

Alle Kapitel: Haskell im Überblick