EMZETT.
Login

Kurz: Jeder Wert hat einen Typ. Mit :: schreibst du ihn hin. Haskell erschließt Typen meist selbst (Typinferenz); Signaturen schreibt man trotzdem für Funktionen auf Top-Level.

Teil des Kurses Haskell

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

Typen

Jeder Wert hat einen Typ. Mit :: schreibst du ihn hin. Haskell erschließt Typen meist selbst (Typinferenz); Signaturen schreibt man trotzdem für Funktionen auf Top-Level.

TypBeispiele
Int42 (feste Größe, 64 Bit)
Integer2^100 (beliebig groß)
Double3.14
BoolTrue, False
Char'a'
String"Text" (= [Char], Liste von Zeichen)
[a][1, 2, 3] Liste
(a, b)(1, "x") Tupel
()Unit
main :: IO ()
main = do
  let n = 42 :: Int
      g = 2 ^ 100 :: Integer
      d = 3.5 :: Double
      c = 'x'
      s = "Haskell"
      t = (1 :: Int, "eins", True)
  print n
  print g
  print d
  print (c, s)
  print t
  print (fst (1, 'a'), snd (1, 'a'))
  print (fromIntegral n * d)
  print (truncate d, round 2.5, round 3.5, ceiling 2.1, floor 2.9)
  print (maxBound :: Int)
  print (show 3.0, show (-2), show [1, 2])

Ausgabe:

42
1267650600228229401496703205376
3.5
('x',"Haskell")
(1,"eins",True)
(1,'a')
147.0
(3,2,4,3,2)
9223372036854775807
("3.0","-2","[1,2]")

Zahlen werden nicht automatisch ineinander umgewandelt: fromIntegral wandelt Int/Integer in andere Zahlentypen um.

Funktionen definieren

quadrat :: Int -> Int
quadrat x = x * x
 
addiere :: Int -> Int -> Int
addiere a b = a + b
 
gruss :: String -> String
gruss name = "Hallo, " ++ name ++ "!"
 
fakultaet :: Integer -> Integer
fakultaet 0 = 1
fakultaet n = n * fakultaet (n - 1)
 
istGerade :: Int -> Bool
istGerade n = n `mod` 2 == 0
 
main :: IO ()
main = do
  print (quadrat 7)
  print (addiere 2 3)
  putStrLn (gruss "Mia")
  print (fakultaet 20)
  print (map istGerade [1 .. 5])

Ausgabe:

49
5
Hallo, Mia!
2432902008176640000
[False,True,False,True,False]

Die Signatur addiere :: Int -> Int -> Int liest sich: “nimmt einen Int, dann einen Int, liefert einen Int”. Das ist kein Zufall:

Currying und partielle Anwendung

Jede Funktion in Haskell hat genau ein Argument. Mehrere Argumente sind verschachtelte Funktionen: addiere 2 ist selbst eine Funktion (Int -> Int).

addiere :: Int -> Int -> Int
addiere a b = a + b
 
main :: IO ()
main = do
  let plus5 = addiere 5          -- partielle Anwendung
  print (plus5 10)
  print (map (addiere 100) [1, 2, 3])
  print (map (* 2) [1, 2, 3])    -- Operator-Abschnitt (section)
  print (map (2 ^) [1, 2, 3, 4])
  print (map (^ 2) [1, 2, 3, 4])
  print (filter (> 2) [1, 2, 3, 4])
  print (map (subtract 1) [5, 6])
  print ((.) (+ 1) (* 2) 5)      -- Komposition: (+1) nach (*2)
  print (((+ 1) . (* 2)) 5)
  print ((\x y -> x * 10 + y) 4 2)   -- Lambda

Ausgabe:

15
[101,102,103]
[2,4,6]
[2,4,8,16]
[1,4,9,16]
[3,4]
[4,5]
11
11
42

Der Punkt . verkettet Funktionen ((f . g) x = f (g x)), $ spart Klammern (f $ g x = f (g x)):

main :: IO ()
main = do
  print $ sum $ map (* 2) $ filter even [1 .. 10]
  print . sum . map (* 2) . filter even $ [1 .. 10]
  putStrLn $ "Ergebnis: " ++ show (length [1, 2, 3])

Ausgabe:

60
60
Ergebnis: 3

Typvariablen und Polymorphie

Kleingeschriebene Typnamen sind Typvariablen: Die Funktion gilt für jeden Typ.

erstes :: (a, b) -> a
erstes (x, _) = x
 
tausche :: (a, b) -> (b, a)
tausche (a, b) = (b, a)
 
zweimal :: (a -> a) -> a -> a
zweimal f = f . f
 
groesser :: Ord a => a -> a -> a      -- a muss vergleichbar sein
groesser x y = if x > y then x else y
 
main :: IO ()
main = do
  print (erstes (1, "x"))
  print (tausche ('a', True))
  print (zweimal (+ 3) 10)
  print (zweimal ('x' :) "y")
  print (groesser 3 7, groesser "apfel" "birne", groesser 2.5 1.5)
  print (id 5, const 1 2, flip (-) 1 10)

Ausgabe:

1
(True,'a')
16
"xxy"
(7,"birne",2.5)
(5,1,9)

Ord a => ist eine Typklasse-Einschränkung (“a muss Ord können”), dazu später mehr.

Merke

  • Typen: Int, Integer, Double, Bool, Char, String, Listen [a], Tupel (a, b)
  • Signatur f :: A -> B -> C; Funktionen haben genau ein Argument (Currying)
  • Partielle Anwendung und Operator-Abschnitte: (+ 1), (2 ^)
  • . verkettet Funktionen, $ spart Klammern, \x -> ... ist ein Lambda
  • Kleine Typbuchstaben (a, b) sind Typvariablen (Polymorphie)

Übungsaufgabe

Schreibe hoch3 :: Int -> Int und wende es mit map auf [1..5] an.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Einführung und erstes Programm

Weiter: Pattern Matching, Guards und Rekursion

Alle Kapitel: Haskell im Überblick