Rein funktional, streng typisiert, elegant
Ausführen: Im Browser mit dem Haskell-Playground (play.haskell.org) oder lokal mit GHC: ghc Hallo.hs && ./Hallo, interaktiv mit ghci.
main :: IO () ist der Einstiegspunkt; do fasst mehrere IO-Aktionen zusammenif und letf x yghci zum Ausprobieren, runghc für Skripteghci # interaktive Umgebung (Ausdrücke direkt testen)
runghc Hallo.hs # Datei wie ein Skript ausführen
ghc Hallo.hs && ./Hallo # kompilieren und starten
cabal run # Projekt startenInt, Integer, Double, Bool, Char, String, Listen [a], Tupel (a, b)f :: A -> B -> C; Funktionen haben genau ein Argument (Currying)(+ 1), (2 ^). verkettet Funktionen, $ spart Klammern, \x -> ... ist ein Lambdaa, b) sind Typvariablen (Polymorphie)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])x : xs); _ ignoriert| bedingung), where, let ... in, case ... of, if ... then ... elsebeschreibe :: 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)head, tail, take, drop, ++, :, !!, zip, lengthmap, filter, foldr/foldl[ausdruck | x <- liste, bedingung]Data.List und Data.Char bieten sort, nub, group, isPrefixOf, toUpper ...foldl' (streng), Data.Map, Data.Vectormain :: 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"])data definiert Typen mit Konstruktoren, Records mit Feldnamenderiving (Show, Eq, Ord, Enum, Bounded) erledigt Routinearbeitclass, instance) beschreiben Verhalten, Ord a => schränkt Typvariablen einSemigroup/Monoid: Werte mit <> zusammenfügendata Farbe = Rot | Gruen | Blau deriving (Show, Eq, Ord, Enum, Bounded)
data Form
= Kreis Double
| Rechteck Double Double
| Dreieck Double Double Double
deriving (Show, Eq)
flaeche :: Form -> Double
flaeche (Kreis r) = pi * r * r
flaeche (Rechteck b h) = b * h
flaeche (Dreieck a b c) = let s = (a + b + c) / 2 in sqrt (s * (s - a) * (s - b) * (s - c))
data Person = Person
{ name :: String
, alter :: Int
, email :: Maybe String
} deriving (Show, Eq)
main :: IO ()
main = do
print [minBound .. maxBound :: Farbe]
print (succ Rot, Rot < Blau, fromEnum Gruen)
mapM_ (print . flaeche) [Kreis 1, Rechteck 3 4, Dreieck 3 4 5]
let mia = Person { name = "Mia", alter = 17, email = Nothing }
aelter = mia { alter = 18, email = Just "mia@example.com" } -- Kopie mit Änderung
print mia
print aelter
putStrLn (name aelter ++ " ist " ++ show (alter aelter))
print (mia == aelter, mia == mia { email = Nothing })Maybe a (Just/Nothing) statt null, Either e a (Left/Right) für Fehler mit GrundfromMaybe, maybe, either, readMaybe, mapMaybefmap/<$>, <*>, >>=: Funktionen über Container und Abläufedo-Notation verkettet Maybe/Either/Listen/IO eleganttraverse/mapM/sequence drehen "Liste von Maybe" zu "Maybe von Liste"import Data.Maybe (fromMaybe, mapMaybe, catMaybes, isJust, fromJust, listToMaybe, maybe)
import Text.Read (readMaybe)
import qualified Data.Map as M
sicherDiv :: Int -> Int -> Maybe Int
sicherDiv _ 0 = Nothing
sicherDiv a b = Just (a `div` b)
main :: IO ()
main = do
print (sicherDiv 10 2, sicherDiv 1 0)
print (fromMaybe 0 (sicherDiv 1 0))
print (maybe "nichts" show (sicherDiv 9 3))
print (readMaybe "42" :: Maybe Int, readMaybe "x" :: Maybe Int, readMaybe "3.5" :: Maybe Double)
print (mapMaybe (\s -> readMaybe s :: Maybe Int) ["1", "x", "3"])
print (catMaybes [Just 1, Nothing, Just 3])
print (lookup "b" [("a", 1), ("b", 2)], M.lookup 5 (M.fromList [(1, "x")]))
print (listToMaybe [9, 8], listToMaybe ([] :: [Int]))
case sicherDiv 20 4 of
Nothing -> putStrLn "Fehler"
Just n -> putStrLn ("Ergebnis " ++ show n)
print (fmap (+ 1) (Just 5), fmap (+ 1) Nothing)
print ((+) <$> Just 3 <*> Just 4, (+) <$> Just 3 <*> Nothing)
print (Just 5 >>= \x -> sicherDiv 100 x >>= \y -> Just (y + 1))
print (isJust (Just 1), (<|>) Nothing (Just 2))
where (<|>) a b = maybe b Just aIO a beschreibt Aktionen; do-Blöcke setzen sie zusammen, <- bindet ErgebnisseforM_, mapM_, when, unless, IORef für Schleifen und Zustand in IOtry, catch, evaluate, finally; im reinen Code Maybe/EitherState führt Zustand ohne Variablen; Parser lassen sich aus Functor/Applicative/Monad bauenimport Data.IORef
import Control.Monad (forM_, when, unless, replicateM_, forM)
main :: IO ()
main = do
putStrLn "Start"
let x = 5 * 5 -- let: reiner Wert
r <- return (x + 1) -- <-: Ergebnis einer Aktion binden
print r
forM_ [1 .. 3] $ \i -> putStrLn ("Runde " ++ show i)
when (x > 10) $ putStrLn "x ist groß"
unless (x > 100) $ putStrLn "x ist nicht riesig"
replicateM_ 2 (putStr "ho ")
putStrLn ""
zaehler <- newIORef (0 :: Int) -- veränderlicher Zustand, explizit in IO
forM_ [1 .. 5] $ \i -> modifyIORef zaehler (+ i)
readIORef zaehler >>= print
quadrate <- forM [1 .. 4] (\i -> return (i * i))
print quadrate
mapM_ print (zip [1 :: Int ..] "abc")
sequence_ [putStr "a", putStr "b", putStrLn "c"]
let aktion = putStrLn "Aktionen sind Werte"
aktion >> aktionimport qualified Data.Map as Map verhindert NamenskonflikteData.Map/Data.Set sind unveränderliche, sortierte BäumeData.Text statt String für Textcontainers, text, mtl, aeson, vectormodule Name (…) whereimport 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')map/filter/fold statt Schleifen, Pattern Matching statt if-KettenMaybe/Either statt null und Exceptions; IO am Rand des Programms-Wall sind deine Werkzeugecabal init --interactive # neues Projekt
cabal build
cabal run mein-projekt
cabal repl # GHCi mit Projekt
cabal test
cabal install --lib containers