Vzory (patterns)
- můžeme definovat pro každý parametr jiné tělo fce
- lucky :: (Integral a) => a -> String
- lucky 7 = "LUCKY NUMBER SEVEN!"
- lucky x = "Sorry, you're out of luck, pal!"
Pro číslo 7 a pro ostatní čísla jsou definovány různá těla fce.
Poznámka: tady jsem si všiml zajímavosti. První řádek specifikuje typ fce (viz předchozí kapitola). Když ho dáme pryč, typ fce bude: lucky :: (Eq a, Num a) => a -> [Char]. Nejspíš je to způsobený odvozováním typu. Když nechám jen poslední řádek s podmínkou pro x obecně, typ fce bude: lucky :: t -> [Char].
Příklad: fce pro výpočet faktoriálu pomocí vzorů (řešení str.36 dole)? A pak zkuste vypočítat faktoriál pro 100 000 a koukejte se na Matrix.
Sčítání 2 vektorů
- addVectors :: (Num a) => (a, a) -> (a, a) -> (a, a)
- addVectors (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)
Vlastní implementace fce head
- head' :: [a] -> a
- head' [] = error "Can't call head on an empty list, dummy!"
- head' (x:_) = x
(x:_) - x zde reprezentuje první prvek z listu a _ jsou zbývající prvky - díky znaku : je zajištěno, že to musí být list. ( a ) jsou potřeba, pokud parsujeme více prvků najednou (zde parsujeme první prvek a zbytek listu)
As patterns
Někdy je potřeba získat celý výraz a i výraz rozdělený podle patternu.- ghci> capital "Dracula"
- "The first letter of Dracula is D"
Fce capital vrátí větu, která obsahuje původní výraz i první písmeno z původního výrazu. Lze to udělat takto:
- capital :: String -> String
- capital "" = "Empty string, whoops!"
- capital (x:xs) = "The first letter of " ++ x:xs ++ " is " ++ [x]
ale i hezčím způsobem:
- capital :: String -> String
- capital "" = "Empty string, whoops!"
- capital all@(x:xs) = "The first letter of " ++ all ++ " is " ++ [x]
Guards
- jedna z možností větvení- bmiTell :: (RealFloat a) => a -> a -> String
- bmiTell weight height
- | weight / height ^ 2 <= 18.5 = "You're underweight, you emo, you!"
- | weight / height ^ 2 <= 25.0 = "You're supposedly normal. Pffft, I bet you're ugly!"
- | weight / height ^ 2 <= 30.0 = "You're fat! Lose some weight, fatty!"
- | otherwise = "You're a whale, congratulations!"
Where
Předchozí příklad není moc DRY. To lze spravit pomocí konstrukce where:- bmiTell :: (RealFloat a) => a -> a -> String
- bmiTell weight height
- | bmi <= skinny = "You're underweight, you emo, you!"
- | bmi <= normal = "You're supposedly normal. Pffft, I bet you're ugly!"
- | bmi <= fat = "You're fat! Lose some weight, fatty!"
- | otherwise = "You're a whale, congratulations!"
- where bmi = weight / height ^ 2
- skinny = 18.5
- normal = 25.0
- fat = 30.0
definujeme jednu vnitřní funkci a tři konstanty na konci vnější funkce. Scope těchto vnitřních fcí a konstant je pro celou vnější fci. Pozor na odsazení jejich odsazení, musejí být stejně odsazené.
Lze použít i pattern matching:
- initials :: String -> String -> String
- initials firstname lastname = [f] ++ ". " ++ [l] ++ "."
- where (f:_) = firstname
- (l:_) = lastname
where funkce mohou být i složitější:
- calcBmis :: (RealFloat a) => [(a, a)] -> [a]
- calcBmis xs = [bmi w h | (w, h) <- xs]
- where bmi weight height = weight / height ^ 2
Zde definujeme vnější funkci calcBmis, kterou používá ve svém těle vnitřní funkci bmi. Vnitřní fce bmi není dostupná zvenku, ale jen uvnitř calcBmis.
Let
- cylinder :: (RealFloat a) => a -> a -> a
- cylinder r h =
- let sideArea = 2 * pi * r * h
- topArea = pi * r ^2
- in sideArea + 2 * topArea
let na rozdíl od where prvně přiřazuje a až pak provádí funkci v bloku in. Rozdíl je též ve scope definovaných funkcí. Let není vidět mezi guardy jako u where. let je také výraz:
- ghci> 4 * (let a = 9 in a + 1) + 2
- 42
Přepis funkce calcBmis do podoby s let:
- calcBmis :: (RealFloat a) => [(a, a)] -> [a]
- calcBmis xs = [bmi | (w, h) <- xs, let bmi = w / h ^ 2]
Rozdíl ve scope, když v ghci napíšeme let s konstrukcí in či bez ní:
- ghci> let zoot x y z = x * y + z
- ghci> zoot 3 9 2
- 29
- ghci> let boot x y z = x * y + z in boot 3 4 2
- 14
- ghci> boot
- <interactive>:1:0: Not in scope: `boot'
Case
- describeList :: [a] -> String
- describeList xs = "The list is " ++ case xs of [] -> "empty."
- [x] -> "a singleton list."
- xs -> "a longer list."
Klasika, lze tu použít i pattern matching.
Žádné komentáře:
Okomentovat