Maybe: Werte, die fehlen können
Statt null gibt es Maybe a: entweder Just wert oder Nothing. Der Compiler zwingt dich, beide Fälle zu behandeln.
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 a(Just 5,Nothing) 0 "3" (Just 42,Nothing,Just 3.5) [1,3] [1,3] (Just 2,Nothing) (Just 9,Nothing) Ergebnis 5 (Just 6,Nothing) (Just 7,Nothing) Just 21 (True,Just 2)
Either: Erfolg oder Fehler mit Grund
Either e a: Left fehler oder Right wert. Konvention: Right ist "richtig".
import Data.Char (isDigit)
data Fehler = Leer | KeineZahl String | ZuGross Int deriving (Show, Eq)
parseAlter :: String -> Either Fehler Int
parseAlter "" = Left Leer
parseAlter s
| not (all isDigit s) = Left (KeineZahl s)
| n > 150 = Left (ZuGross n)
| otherwise = Right n
where n = read s
pruefe :: Int -> Either Fehler String
pruefe a = Right (if a >= 18 then "volljährig" else "minderjährig")
main :: IO ()
main = do
print (map parseAlter ["17", "", "abc", "200"])
print (parseAlter "30" >>= pruefe)
print (parseAlter "x" >>= pruefe)
print (fmap (* 2) (parseAlter "21"))
print (either show (\a -> "Alter " ++ show a) (parseAlter "12"))
print (traverse parseAlter ["1", "2", "3"])
print (traverse parseAlter ["1", "x", "3"])
let ergebnis = do -- do-Notation für Either
a <- parseAlter "40"
b <- parseAlter "2"
Right (a + b)
print ergebnis[Right 17,Left Leer,Left (KeineZahl "abc"),Left (ZuGross 200)] Right "vollj\228hrig" Left (KeineZahl "x") Right 42 "Alter 12" Right [1,2,3] Left (KeineZahl "x") Right 42
Das Ergebnis Left bricht die Kette ab (wie eine Exception), ohne Ausnahmen zu werfen: Fehler sind Werte im Typ.
Functor, Applicative, Monad
Alle bisherigen Typen (Maybe, Either, Listen, IO) gehören zu denselben Typklassen:
| Klasse | Funktion | Idee |
|---|---|---|
Functor | fmap f x bzw. f <$> x | Funktion in den Container anwenden |
Applicative | pure x, f <*> x | Funktionen im Container anwenden, kombinieren |
Monad | x >>= f | Abläufe verketten, bei denen jeder Schritt vom vorigen abhängt |
main :: IO ()
main = do
print (fmap (* 2) [1, 2, 3], (+ 1) <$> Just 1, fmap length (Right "abc" :: Either Int String))
print (pure 5 :: [Int], pure 5 :: Maybe Int)
print ((+) <$> [1, 2] <*> [10, 20]) -- alle Kombinationen
print ((,) <$> Just 'a' <*> Just True)
print ([1, 2, 3] >>= \x -> [x, x * 10])
print (do { x <- [1, 2]; y <- "ab"; return (x, y) })
print (sequence [Just 1, Just 2], sequence [Just 1, Nothing])
print (mapM (\x -> if x > 0 then Just x else Nothing) [1, 2, 3])
print (zipWith3 (\a b c -> a + b + c) [1, 2] [10, 20] [100, 200])
print (fmap (+ 1) (3, 4), fst <$> Just (1, 2))
print (concat <$> mapM (\x -> Just [x, x]) [1, 2])([2,4,6],Just 2,Right 3)
([5],Just 5)
[11,21,12,22]
Just ('a',True)
[1,10,2,20,3,30]
[(1,'a'),(1,'b'),(2,'a'),(2,'b')]
(Just [1,2],Nothing)
Just [1,2,3]
[111,222]
((3,5),Just 1)
Just [1,1,2,2]Merke
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/sequencedrehen "Liste von Maybe" zu "Maybe von Liste"
Aufgabe
Schreibe sicherWurzel :: Double -> Maybe Double und verkette zwei Aufrufe mit >>=.