programování v haskellu - univerzita karlovakratochvil/haskell/slides.pdf• návrhové vzory z...
TRANSCRIPT
![Page 1: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/1.jpg)
Programování v Haskellu
KSI MFF CUNI CZ2019
1
![Page 2: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/2.jpg)
Úvod a předběžnosti
![Page 3: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/3.jpg)
Meta, požadavky
NPRG068, 2/0 Zk, 3 kredity
http://ksi.mff.cuni.cz/~kratochvil/haskell
2
![Page 4: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/4.jpg)
Požadavky
1. Domácí úkoly — využití prostředků jazyka• rozsah cca. 5% LOC úkolů z Javy a C++• Zadání budou na webu• Předběžný rozvrh:
Úkol Zadání Termín (Týdny)1 10. 10. 31. 10. 2–52 31. 10. 21. 11. 5–83 21. 11. 12. 12. 8–11
2. Zkouška — max 5–10 minut lehce teoretické diskuze• zhodnocení odevzdaných úkolů• témata budou vyvěšená na webu• témata⊂ obsah slajdů• obtížnost: po zvládnutí DÚ zanedbatelná, myšleno spíš jako kontrola a
doplnění
3
![Page 5: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/5.jpg)
Co je potřeba do kdy stihnout?
• Odevzdat úkoly v termínu.Termín je do půlnoci dne označeného jako termín (tj. první úkol bysteměli začít odevzdávat nejpozději 31. 10. ve 23:59:59).Pokud nebudete stíhat, dejte vědět předem.
• Jít na zkoušku.Termíny a předtermíny budou v SISu.
4
![Page 6: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/6.jpg)
DÚ — požadavky
• Velikost řešení není vhodné přehánět (čím menší, tím lepší!)
• Správnost:• Rozumné použití typového systému pro prevenci běhových chyb• Rozumná časová složitost použitých algoritmů
5
![Page 7: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/7.jpg)
DÚ — odevzdávání
1. Z řešení vyrobte cabalový balík2. Použijte cabal sdist
3. výsledek nahrajte do odpovídající kolonky SISu.
6
![Page 8: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/8.jpg)
Obsah přednášky
1. opakování z neprocedurálního programování2. šťourání v typech, monádách a IO3. standardní knihovna4. implementace jazyka, RTS, typového systému a modularizace5. nejužitečnější ostatní abstrakce a knihovny
7
![Page 9: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/9.jpg)
Slajdy
Slajdy jsou volně k dispozici na webu.
Pokud najdete chybu nebo vymyslíte zlepšení:
• řekněte si o git access (implementace: lhs2TeX + beamer)• malé věci reportujte mailem
Typické zlepšení: ilustrativní obrázek obsahující kočku.
8
![Page 10: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/10.jpg)
Proč sem chodit?
• návrhové vzory z funkcionálního programování a Haskellu jsou jedny znejmladších a nejužitečnějších věcí, které komunita má
• haskellové programy nepadají(tj.: haskellové programy nepadají z hloupých důvodů)
• funkcionální programování je Opravdu Hodně Expresivní• důsledek: průmysl začíná chtít funkcionální programátory
(ještě se musí zjistit, že Scala je fakt úlet)• zjistíte i něco o ostatních jazycích
9
![Page 11: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/11.jpg)
Proč sem chodit?
• Bonus 1: Haskellová praxe dramaticky zlepšuje schopnost programovatbez chyb ve všech ostatních jazycích.Programátor umí z libovolného typecheckeru vyždímat maximum.
• Bonus 2: Hodně temných a těžko vysvětlitelných jevů z C++ má vHaskellu svou pochopitelnější variantu.
10
![Page 12: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/12.jpg)
Stručná historie
10
![Page 13: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/13.jpg)
Industry-ready
10
![Page 14: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/14.jpg)
10
![Page 15: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/15.jpg)
Expresivní!
wordCount = length · words 〈$〉 readLine
rle = map (liftA2 (, ) head length) · group
scc g = dfs g · reverse · postOrd $ transposeG g
11
![Page 16: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/16.jpg)
11
![Page 17: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/17.jpg)
12
![Page 18: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/18.jpg)
Literatura
• Learn You A Haskell For Great Goodhttp://learnyouahaskell.com/
• Real World Haskellhttp://book.realworldhaskell.org/
• Hooglehttps://hoogle.haskell.org/
• Typeclassopædia• Haskell Wikibook...
13
![Page 19: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/19.jpg)
Okolní předměty
• NPRG005 Neproc• typový systém Haskellu je skoro Prolog!• hlavním účelem NPRG005 je naučit se rekurzi, tady budeme trochu blíž
normálnímu programování• NAIL078, NAIL079 Lambda kalkulus a funkcionální programování
• (ne)rozhodnutelnost, typové systémy, souvislost s logikou• NAIL097 Funkcionální programování
• sémantika, typové systémy víc zblízka• občas Agda a kategorie
14
![Page 20: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/20.jpg)
Okolní jazyky
• Haskell je ‘managed’ — o napojení na systém se stará run-time.• Nelze s ním (úplně) nahradit nízkoúrovňové jazyky (C, C++, Rust).• Je velmi vhodné naplno využít potenciál run-time vrstvy a Haskellem
nahrazovat různé polovičaté C-like managed jazyky — typicky Javu aC#, běžně se stonásobnou úsporou kódu, času, chyb, rychlosti a nervů.
• Haskell je ‘typovaný’ a ‘kompilovaný’ — nelze s ním (úplně) nahraditshell-like jazyky (Bash, R, K, . . . ), ale jde se k tomu dost přiblížit.
• Haskell není ‘browserový’, ale jde (s trochou opatrnosti) kompilovat doJavaScriptu.
15
![Page 21: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/21.jpg)
Aktuální obsah slajdů1. Úvod a předběžnosti
2. Rychloúvod do funkcionálního programování
3. Praxe s monádami: Parsovací kombinátory
4. Balíčky a knihovny
5. Tour de Prelude
6. Kontejnery
7. Kompilujeme Haskell
8. Curry-Howardova korespondence
9. Optika, čočky a hranoly
10. Stringologie a formátování textu
11. IO!
12. Transformujeme monády
13. Grafické knihovny
14. Debugování, testování, benchmarking
15. Webové aplikace
16
![Page 22: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/22.jpg)
Rychloúvod do funkcionálního programování
![Page 23: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/23.jpg)
Kde sehnat prostředí
Windows/Mac: Nainstalujte si Haskell Platform.
• https://www.haskell.org/platform/
Unix-compatible: Použijte oblíbený balíčkovač.
• apt-get install ghc
• yum install ghc
• pkg install ghc
• . . .• ArchLinux: ghc-static, cabal-static!• Distro-agnostic: ghcup
Ve vlastním zájmu používejte nějaký unix.
17
![Page 24: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/24.jpg)
Hello
$ cat > hello.hs <<EOHSmain = putStrLn "Hello MFF!"EOHS$ runhaskell hello.hsHello MFF!$ ghc hello.hs -o hello[1 of 1] Compiling Main ( hello.hs, hello.o )Linking hello ...$ ./helloHello MFF!
18
![Page 25: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/25.jpg)
Interpreter
$ ghci hello.hsGHCi, version 8.2.2[1 of 1] Compiling Main ( hello.hs, interpreted )Ok, one module loaded.*Main> :t mainmain :: IO ()*Main> mainHello MFF!*Main> 5+510
19
![Page 26: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/26.jpg)
Integrace s nástroji
Standardní pomůcky: hindent, hlint.
Editory:
• vim: Hashell-vim-now, Syntastic, neco-ghc• emacs: spacemacs + haskell-mode, stack+intero• obecně: ghc-mod
IDE škodí kvalitě kódu. Pokud váš kód nebude číst nikdo jiný a bez IDEneumíte žít, můžete zkusit:
• leksah• pluginy do IntelliJ, Eclipse, KDevelop
20
![Page 27: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/27.jpg)
Syntax
Haskell je deklarativní jazyk, program je hromada definovaných hodnot:
jmenoHodnoty = definiceHodnoty
hodnotaSParametrem parametr = definice
Pokud je v programu hodnota main, runtime ji pro “spuštění” programu“vyhodnotí”.
main = print (1 + 1)
21
![Page 28: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/28.jpg)
Syntax výrazů
• Jména proměnných začínají malým písmenem: a b ahoj• Literály: 123, 1.5, ’a’, "nazdar"• 2 výrazy za sebou = aplikace funkce na parametr:
• negate 5• take 3 "kocka"
• operátory mají nižší prioritu než aplikace!• +, - ,++, ==, >=, <=, . . .• negate 5− 10 ;?
• kulaté závorky:• take 1 + 2 "kocka"• take (1 + 2) "kocka"
22
![Page 29: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/29.jpg)
Operátory
Vlastní operátory jde definovat s asociativitou a prioritou:
infixr 3 ++
infixl 6 /%/
infix 5 :=>
Operátor jde předělat na funkci uzávorkováním:
5 + 10 ; 15(+) 5 10 ; 15
Identifikátor ve zpětných apostrofech je operátor:
mod 10 3 ; 110 ‘mod‘ 3 ; 1
Pozor na unární mínus.23
![Page 30: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/30.jpg)
Syntax funkcí
Funkci jde definovat jako definici s parametrem:
f a b c = b∧2− 4 ∗ a ∗ c
nebo ekvivalentně jako lambdu:
f = λa b c→ b∧2− 4 ∗ a ∗ c
nebo ekvivalentně úplně rozdrobit:
f = λa→ λb→ λc→ b∧2− 4 ∗ a ∗ c
• pojmenovávat lambdy není nutné• λ se píše jako zpětné lomítko
24
![Page 31: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/31.jpg)
Lokální definice
Občas se hodí mít něco zadefinovaného lokálně.
solve a b c =
let d = b∧2− 4 ∗ a ∗ csolution op = (−b ‘op‘ sqrt d) / (2 ∗ a)
in (solution (+), solution (−))
To samé obráceně:
solve a b c = (solution (+), solution (−))
where d = b∧2− 4 ∗ a ∗ csolution op = (−b ‘op‘ sqrt d) / (2 ∗ a)
25
![Page 32: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/32.jpg)
Řízení výpočtu
if cond then a else b
• cond musí být booleovská hodnota• “if bez else” nedává matematicky smysl (jaký typ má nic?)
case x ofmoznost1→ vysledek1moznost2→ vysledek2→ necoJineho
26
![Page 33: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/33.jpg)
Řízení výpočtu 2
Pattern matching:
fac 0 = 1fac n = n ∗ fac (n− 1)
Guards:
gcd x y| x < y = gcd y x| x ≡ y = x| x > y = gcd y (x ‘mod‘ y)
| otherwise = ⊥ -- error
27
![Page 34: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/34.jpg)
Kritické vlastnosti jazyka
• Haskell je líný! Prakticky žádnou funkci nevyhodnotí, dokud to nebudepřímo potřeba.Důsledek: nekonečná data jsou OKallIntsFrom n = n : allIntsFrom (n + 1)
• Haskell je staticky typovaný!Důsledky:
• při běhu nevznikne chyba z typových důvodů• znalost typů lze při překladu různě využívat
28
![Page 35: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/35.jpg)
Cykly jsou ve funkcionálním jazyce zbytečné.
(jdou plně nahradit rekurzí)
28
![Page 36: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/36.jpg)
Cykly jsou ve funkcionálním jazyce zbytečné.
(jdou plně nahradit rekurzí)
28
![Page 37: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/37.jpg)
Typy
Názvy jednoduchých typů začínají velkým písmenem, typy je možnéspecifikovat pomocí čtyřtečky.
cislo :: Integercislo = 5jineCislo = (5 :: Float)
V ghci je možné typ čehokoliv zjistit pomocí :t.
29
![Page 38: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/38.jpg)
Typy funkcí
id :: a→ a
...ve skutečnosti: id :: (∀a) a→ atj. neplatí id :: Int→ a ani id :: a→ Int.
(, ) :: a→ b→ (a, b)
(·) :: (b→ c)→ (a→ b)→ (a→ c)head :: [a]→ a(+) :: Num a⇒ a→ a→ a
...tzn. (+) :: (∀a ∈ Num) a→ a→ a
Monomorfní:
id :: Int→ Intgcd :: Integer → Integer → Integer
30
![Page 39: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/39.jpg)
Curry-style parametry
Víceparametrové funkce neexistují!
f :: Int→ Int→ Int→ Intf 1 2 3 :: Intf :: Int→ (Int→ (Int→ Int))
f 1 :: Int→ (Int→ Int)(f 1) 2 :: Int→ Int((f 1) 2) 3 :: Int
Související kombinátory:
curry :: ((a, b)→ c)→ (a→ b→ c)uncurry :: (a→ b→ c)→ ((a, b)→ c)
31
![Page 40: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/40.jpg)
Haskell Curry
31
![Page 41: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/41.jpg)
Curry-style parametry
Koncept porodil Schönfinkel (1924), v kombinátorové logice populárně použilaž Curry.
Samozřejmě k dispozici je i varianta schön, unschön.
32
![Page 42: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/42.jpg)
Moses Schönfinkel
“Arity pls.”
32
![Page 43: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/43.jpg)
Kontrolní otázka: Kolik parametrů má funkce id :: a→ a?
Odpověď: počty parametrů jsou blbost!
id 5id gcd 10 15id id gcd 10 15
33
![Page 44: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/44.jpg)
Kontrolní otázka: Kolik parametrů má funkce id :: a→ a?
Odpověď: počty parametrů jsou blbost!
id 5id gcd 10 15id id gcd 10 15
33
![Page 45: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/45.jpg)
Některé jednoduché typy
• 1 :: Int, Integer,Word, Int64, . . .• ’c’ :: Char,Word8, . . .• 1.23 :: Float,Double• True :: Bool, False :: Bool• () — existující nicneříkající typ• Void — neexistující nicneříkající typ
34
![Page 46: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/46.jpg)
Některé parametrizované typy
• [a] — seznam[1, 2, 3] :: Num a⇒ [a]
• type String = [Char ]• Maybe a
• [ Just ’c’,Nothing ] :: [Maybe Char ]
35
![Page 47: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/47.jpg)
Definice algebraických datových typů
data Bool = False | Truedata () = ()
data Void
Typy s obsahem:
data DvojiceIntu = Par Int Int
Konstrukce:
Par 2 3 :: DvojiceIntu
Destrukce (a.k.a. pattern match):
f :: DvojiceIntu→ Intf (Par a b) = b
36
![Page 48: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/48.jpg)
Parametrické typy
Parametry jako u funkcí (jen na jiném univerzu):
data Maybe a = Nothing | Just adata (, ) a b = (, ) a bdata Either a b = Left a | Right bdata (→) a b -- internal
Maybe, (, ) a (→) jsou typové konstruktory (v jazyce typů).
Nothing, Just a (, ) jsou datové konstruktory (v jazyce termů).
Konvence: Typové a datové konstruktory začínají velkým písmenem. Typovéa datové proměnné začínají malým písmenem. (účel: přehlednost kódu,zjednoznačnění některých konstrukcí)
37
![Page 49: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/49.jpg)
Parametrické typy
data Dvojice a = Dva a aDva 1 2 :: Dvojice IntDva (Just 5) Nothing :: Dvojice (Maybe Int)Dva True 3 -- type error
38
![Page 50: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/50.jpg)
Seznam
data [a] = (a : [a]) | [ ]
...přeloženo:
data [ ] a = (:) a ([ ] a) | [ ]
1 : 2 : 3 : [ ] ≡ [1, 2, 3]
39
![Page 51: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/51.jpg)
Kind
Jak se zkontroluje správné použití typů a jejich parametrů?
Typům typů se říká Kinds (‘druhy’). Všechny typy hodnot patří do druhu ∗.
Bool :: ∗Int :: ∗Maybe :: ∗ → ∗Maybe Int :: ∗[ ] :: ∗ → ∗(→) :: ∗ → ∗ → ∗RWST :: ∗ → ∗ → ∗ → (∗ → ∗)→ ∗Num :: ∗ → Constraint
V ghci se zjistí pomocí :k.
40
![Page 52: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/52.jpg)
Ostatní definice typů
Typová synonyma (obě strany jsou ekvivalentní):
type DvaInty = (Int, Int)
“Unboxed data” (typ se zkontroluje a pak se odmaže):
newtype DvaInty = DvaInty (Int, Int)
41
![Page 53: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/53.jpg)
Výběr z Prelude
fst :: (a, b)→ asnd :: (a, b)→ bshow :: Show a⇒ a→ Stringread :: Read a⇒ String→ aputStrLn :: String→ IO ()
getLine :: IO Stringprint :: Show a⇒ a→ IO ()
readLn :: Read a⇒ IO a($) :: (a→ b)→ a→ b(·) :: (b→ c)→ (a→ b)→ (a→ c)
42
![Page 54: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/54.jpg)
Výběr ze Prelude — seznamy
head, last :: [a]→ atail, init :: [a]→ [a]
(++) :: [a]→ [a]→ [a]
(!!) :: [a]→ Int→ aelem :: [a]→ a→ Boollength :: [a]→ Inttake, drop :: Int→ [a]→ [a]
takeWhile, dropWhile :: (a→ Bool)→ [a]→ [a]
lines,words :: String→ [String ]
unlines, unwords :: [String ]→ Stringmap :: (a→ b)→ [a]→ [b]
filter :: (a→ Bool)→ [a]→ [a]
foldl :: (a→ x→ a)→ a→ [x ]→ afoldr :: (x→ a→ a)→ a→ [x ]→ alookup :: Eq a⇒ a→ [(a, b)]→ Maybe b 43
![Page 55: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/55.jpg)
Dolary a tečky
LISP/Python:
wordList docs = sort (nub (concat (map words docs)))
Trochu lepší:
wordList docs = sort $ nub $ concat $ map words docs
Ještě lepší:
wordList docs = sort · nub · concat ·map words $ docs
Nejlepší:
wordList = sort · nub · concat ·map words
44
![Page 56: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/56.jpg)
Jak na IO
I/O není vedlejší efekt!
Místo toho máme speciální konstrukce, které dovolují hodnoty typu IO akombinovat a vyrábět z nich větší IO hodnoty.
main =
do a← getLineprintNums 0 (read a)
printNums :: Int→ Int→ IO ()
printNums a b| a > b = return ()
| otherwise = do print aprintNums (a + 1) b
main :: IO () je IO akce která popisuje externí komunikaci celého programu.
45
![Page 57: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/57.jpg)
Praktikum
group [ ] = [ ]
group l@(x: _) = takeWhile (≡ x) l: group (dropWhile (≡ x) l)
qsort [ ] = [ ]
qsort (x : xs) = qsort a ++ x : qsort bwhere a = filter (<x) xs
b = filter (> x) xsrle = map (λl→ (head l, length l)) · group
group :: Eq a⇒ [a]→ [[a]]
sort :: Ord a⇒ [a]→ [a]
rle :: Eq a⇒ [a]→ [(a, Int)]
46
![Page 58: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/58.jpg)
Praktikum
group [ ] = [ ]
group l@(x: _) = takeWhile (≡ x) l: group (dropWhile (≡ x) l)
qsort [ ] = [ ]
qsort (x : xs) = qsort a ++ x : qsort bwhere a = filter (<x) xs
b = filter (> x) xsrle = map (λl→ (head l, length l)) · group
group :: Eq a⇒ [a]→ [[a]]
sort :: Ord a⇒ [a]→ [a]
rle :: Eq a⇒ [a]→ [(a, Int)]
46
![Page 59: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/59.jpg)
Praktikum — laziness
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)findMin = head · qsort
Jakou má časovou složitost findMin?
47
![Page 60: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/60.jpg)
Jednodušší typové třídy
třída operaceEq (≡), ( 6≡)
Ord (<), (6), compare, . . .Enum [1..10], [False..]Num (+), (−), (∗), abs, . . .Integral div,mod, . . .Fractional (/), . . .Floating π, sin, cos, exp, log, logBase, sqrt, . . .Show showRead read
48
![Page 61: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/61.jpg)
Číselná hierarchie
Enum
Bounded
Eq
Ord
Num
Real
Fractional
Floating
RealFrac RealFloatIntegral
minBound,maxBound
succ, pred,enumFromTo
(==)
(<), min, max
(+), (-), (*),fromInteger
toRational
(/), recip, fromRa-tional
pi, exp, logBase,sqrt, (**), sin, cos,tan, asin, . . .
truncate, round,ceiling, floor
exponent,significand,
saleFloat, isNaN,isInfinite, atan2
quot, rem, div,mod, toInteger
49
![Page 62: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/62.jpg)
Číselná hierarchie vs. počítače
toRational 0.1; 3602879701896397 % 36028797018963968
ceiling (1.0 / 0.0)
17976931348623159077293051907890247336179 ...
50
![Page 63: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/63.jpg)
Overloading
Typové třídy existují kvůli přetěžování funkcí.
C-style přetěžování (“ad-hoc overloading”) je možné jen s jednosměrnýmtypovým systémem, v Haskellu by bylo NP-úplné.
class Moje a wheremoje :: a→ a→ a
instance Moje Int wheremoje = (+)
instance Moje String wheremoje = (++)
moje 1 3 ; 4moje "ah" "oj" ; "ahoj"
51
![Page 64: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/64.jpg)
Overloading — příklad
newtype I7 = I7 Intinstance Num I7 where
(+) = i7lift2 (+)
(−) = i7lift2 (−)
(∗) = i7lift2 (∗)negate = i7lift negateabs = idsignum (I7 0) = I7 0signum = I7 1fromInteger i = I7 $ i ‘mod‘ 7
i7lift f (I7 a) = I7 (f a ‘mod‘ 7)
i7lift2 f (I7 a) (I7 b) = I7 (f a b ‘mod‘ 7)
52
![Page 65: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/65.jpg)
Overloading — příklad 2
data Infinite a = MinusInf | Finite a | PlusInfinstance Ord a⇒ Ord (Infinite a) wherecompare (Finite a) (Finite b) = compare a bcompare MinusInf MinusInf = EQcompare MinusInf = LTcompare MinusInf = GTcompare PlusInf PlusInf = EQcompare PlusInf = GTcompare PlusInf = LT
53
![Page 66: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/66.jpg)
Overloading — příklad 3
instance Num a⇒ Num [a] where(+) = zipWith (+)
(−) = zipWith (−)
(∗) = zipWith (∗)negate = map negateabs = map abssignum = map signumfromInteger = repeat · fromInteger
3 ∗ [1, 2, 3] + 2 ; [5, 8, 11]
fibs = 0 : 1 : fibs + tail fibs
54
![Page 67: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/67.jpg)
Typové třídy nejsou interface!
OOP: INumeric doSomething(INumeric a)
vs.
Haskell: doSomething :: Num a⇒ a→ a
Kde je rozdíl?
55
![Page 68: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/68.jpg)
Typové třídy nejsou subtyping!
C-like: (long)(double)(int)(float)5 je OK, integery jdouautomaticky konvertovat.
Haskell: ((5 :: Float) :: Int) je chyba!
Jak se tedy integer 5 zkonvertuje na float?!
Desugaring literálů: pětka se přepíše na fromInteger 5, kde 5 je pevnáIntegerová hodnota.
fromInteger :: Num a⇒ Integer → a
Důsledek: 5 :: Num a
(konverze se většinou inlinuje a nemá runtime overhead)
56
![Page 69: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/69.jpg)
Typové třídy nejsou subtyping!
C-like: (long)(double)(int)(float)5 je OK, integery jdouautomaticky konvertovat.
Haskell: ((5 :: Float) :: Int) je chyba!
Jak se tedy integer 5 zkonvertuje na float?!
Desugaring literálů: pětka se přepíše na fromInteger 5, kde 5 je pevnáIntegerová hodnota.
fromInteger :: Num a⇒ Integer → a
Důsledek: 5 :: Num a
(konverze se většinou inlinuje a nemá runtime overhead)
56
![Page 70: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/70.jpg)
Moc teoretické?
56
![Page 71: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/71.jpg)
Get something cool on screen in 10 minutes!
import Graphics.Glossmain = animate FullScreen white $ λt→let blink ph sp = (1 + sin (ph+ t ∗ sp)) / 2in Pictures $ flip map [1 . . 4] $ λx→Rotate (90 ∗ x + 20 ∗ t) $Translate (80 + 40 ∗ cos t) 0 $Color (makeColor (blink 0 1)
(blink 3 1)(blink 0 π)1) $
ThickCircle 20 3 56
![Page 72: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/72.jpg)
56
![Page 73: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/73.jpg)
Pologrupy a monoidy
class Semigroup a where(�) :: a→ a→ a
class Semigroup a⇒ Monoid a wheremempty :: a
Obecnější operace slepování (píše se jako <>):
[1, 2] � [4, 5] ; [1, 2, 4, 5]
"ah" � "oj" ; "ahoj" -- i pro Text a ByteStringJust [1, 2] � Nothing � Just [3] ; Just [1, 2, 3]
EQ � LT � GT ; LTmempty :: Maybe a ; Nothing
Nad množinou čísel existuje víc monoidů:
Sum 5 � Sum 3 ; Sum 8Product 5 � Product 3 ; Product 15(mempty :: Product Int) ; Product 1
57
![Page 74: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/74.jpg)
Kontejnerovitost
data Tree a = Nil | Branch (Tree a) a (Tree a)
map (+1) [1, 2, 3] ; [2, 3, 4]
map (+1) (Branch Nil 1 (Branch Nil 2 Nil)) -- error
Co takhle přetížit map?
class Functor f wherefmap :: (a→ b)→ (f a→ f b)
Pozor, f má kind ∗ → ∗.
instance Functor Tree wherefmap Nil = Nilfmap f (Branch l a r) = Branch (fmap f l) (f a) (fmap f r)
fmap (+1) [1, 2, 3] ; [2, 3, 4]
fmap (+1) (Branch Nil 1 (Branch Nil 2 Nil))
; Branch Nil 2 (Branch Nil 3 Nil)
58
![Page 75: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/75.jpg)
Kontejnerovitost
data Tree a = Nil | Branch (Tree a) a (Tree a)
map (+1) [1, 2, 3] ; [2, 3, 4]
map (+1) (Branch Nil 1 (Branch Nil 2 Nil)) -- error
Co takhle přetížit map?
class Functor f wherefmap :: (a→ b)→ (f a→ f b)
Pozor, f má kind ∗ → ∗.
instance Functor Tree wherefmap Nil = Nilfmap f (Branch l a r) = Branch (fmap f l) (f a) (fmap f r)
fmap (+1) [1, 2, 3] ; [2, 3, 4]
fmap (+1) (Branch Nil 1 (Branch Nil 2 Nil))
; Branch Nil 2 (Branch Nil 3 Nil) 58
![Page 76: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/76.jpg)
Kontejnerovitost
(〈$〉) = fmap(∗2) 〈$〉 [2, 3, 4] ; [4, 6, 8]
(+1) · (+2) 〈$〉 Just 5 ; Just 8
uncurry gcd 〈$〉 Just (1024, 768) ; Just 256
fmap show 〈$〉 [Nothing, Just 3, Just 4]
; [Nothing, Just "3", Just "4"]
59
![Page 77: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/77.jpg)
59
![Page 78: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/78.jpg)
Rozumné funktory
fmap id ≡ id
fmap f · fmap g ≡ fmap (f · g)
59
![Page 79: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/79.jpg)
Funkce jako data
Funkce jsou kontejnery na výsledky.
instance Semigroup b⇒ Semigroup (a→ b) wheref � g = λa→ f a � g a
instance Monoid b⇒ Monoid (a→ b) wheremempty = \_→ mempty
(drop 3 � take 3) [1, 2, 3, 4, 5] ; [4, 5, 1, 2, 3]
(drop � take) 2 [1, 2, 3, 4, 5] ; [3, 4, 5, 1, 2]
Podobně:
instance Functor ((→) p) wherefmap = (·)
fmap :: (a→ b)→ ((p→ a)→ (p→ b))
(show 〈$〉 (∗3)) :: Int→ String(show 〈$〉 (∗3)) 3 ; "9"
(“obsah” se z “kontejneru” dostane dodáním parametru) 60
![Page 80: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/80.jpg)
Funkce jako data
instance Num b⇒ Num (a→ b) where(f + g) x = f x + g x(f ∗ g) x = f x ∗ g xnegate f x = negate (f x)
fromInteger n x = fromInteger nsignum f x = signum (f x)
abs f x = abs (f x)
(sin∧2 + cos∧2) 4.64234 ; 1.0(sin + 1) 1 ; 1.8414709848078965(sin + 1) π ; 1.0000000000000002(negate negate) 5 ; 53 7 ; 3((+) ∗ (−)) 7 5 ; 24
61
![Page 81: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/81.jpg)
Funkce vs. kontejnery
($) :: (a→ b)→ ( a → b)
map :: (a→ b)→ ([a]→ [b])
fmap :: (a→ b)→ (f a → f b)
:: f (a→ b)→ (f a → f b)
Co když je původní funkce taky v kontejneru?
62
![Page 82: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/82.jpg)
Funkce vs. kontejnery
Např.:
let a = getProgram :: d→ rb = getData :: d
in a b
Když získávání programu nebo dat může selhat, použijeme Maybe:
let a = getProgram :: Maybe (d→ r)b = getData :: Maybe d
in a ‘ap‘ bwhere ap (Just l) (Just r) = Just (l r)
ap = Nothing
63
![Page 83: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/83.jpg)
Applicative
Koncept aplikace “obalené” funkce je zachycený ve třídě Applicative:
class Functor f ⇒ Applicative f wherepure :: a→ f a(〈∗〉) :: f (a→ b)→ f a→ f b
Just show 〈∗〉 Just 3 ; Just "3"(pure show 〈∗〉 pure 3) :: Maybe String ; Just "3"Nothing 〈∗〉 Just 3 ; NothingJust show 〈∗〉 Nothing ; NothingJust gcd 〈∗〉 Just 1024 〈∗〉 Just 768 ; Just 256(pure show 〈∗〉 pure 3) :: [String ] ; ["3"]
64
![Page 84: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/84.jpg)
Instance Applicative
instance sémantikaMaybe selháváníEither l selhávání s chybou typu l[ ] množiny výsledků výpočtu(→) p výpočet s globálním parametrem
65
![Page 85: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/85.jpg)
Příklady Applicative
Just (, ) 〈∗〉 Just 3 〈∗〉 pure 5 ; Just (3, 5)
(, ) 〈$〉 pure 3 〈∗〉 Just 5 ; Just (3, 5)
((+) 〈$〉 pure 3 〈∗〉 pure 7) :: Either String Int; Right 10
(+) 〈$〉 Right 3 〈∗〉 pure 7; Right 10
(+) 〈$〉 pure 3 〈∗〉 Left "sorry error"; Left "sorry error"
[(+1), (+2), negate] 〈∗〉 [2, 3, 4]
; [3, 4, 5, 4, 5, 6,−2,−3,−4]
rle = map ( (, ) 〈$〉 head 〈∗〉 length) · grouprle′ = map (liftA2 (, ) head length) · group
66
![Page 86: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/86.jpg)
Rozumné aplikativní funktory
pure id 〈∗〉 a ≡ a
pure (a b) ≡ pure a 〈∗〉 pure b
a 〈∗〉 pure b ≡ pure ($b) 〈∗〉 a
a 〈∗〉 (b 〈∗〉 c) ≡ pure (·) 〈∗〉 a 〈∗〉 b 〈∗〉 c
66
![Page 87: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/87.jpg)
Applicative vs. monoid
Užitečná demonstrativní instance:
instance Monoid a⇒ Applicative ((, ) a) wherepure x = (mempty, x)
(u, f) 〈∗〉 (v, x) = (u � v, f x)
("hello ", (+17)) 〈∗〉 ("world!", 2002)
; ("hello world!", 2019)
67
![Page 88: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/88.jpg)
Funkce vs. kontejnery II.
($) :: (a→ b)→ ( a→ b)
fmap :: (a→ b)→ (f a→ f b)
(〈∗〉) :: f (a→ b)→ (f a→ f b)
:: (a→ f b)→ (f a→ f b)
Jde funkci, jejíž výsledek je obalený nějakou sémantikou (např.: může selhat,nebo možných výsledků může být víc), předělat na funkci, která tento obalspojí s již existujícím obalem?
Podobný problém z jiné strany:
join :: f (f a)→ f a
68
![Page 89: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/89.jpg)
Spojování Applicative
Příklad sMaybe: Nějaké funkce můžou selhat, potřebujeme z nich vyrobitjednu uniformně selhávající funkci.
lookup :: Eq a⇒ a→ [(a, b)]→ Maybe blookup4 :: Eq a⇒ a→ [(a, a)]→ Maybe alookup4 a l = case lookup a l ofNothing→ NothingJust a′ → case lookup a′ l ofNothing→ NothingJust a′′ → case lookup a′′ l ofNothing→ NothingJust a′′′ → lookup a′′′ l
SW Engineering: Vytrhněme kus opakujícího se kódu!
69
![Page 90: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/90.jpg)
andThen
andThen :: Maybe a→ (a→ Maybe b)→ Maybe bandThen Nothing = NothingandThen (Just a) f = f alookup4 a l = lookup a l ‘andThen‘ λa→
lookup a l ‘andThen‘ λa→lookup a l ‘andThen‘ λa→lookup a l
Trochu lepší!
70
![Page 91: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/91.jpg)
andThen (na steroidech)
infixr 1 ‘andThen‘lookup4 a l = go a ‘andThen‘ go
‘andThen‘ go‘andThen‘ go
where go a = lookup a l
70
![Page 92: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/92.jpg)
Seznamy
Úkol: Robot za jednu časovou jednotku může jít do nějakých (na pozicizávislých) směrů, tam může udělat nějaké (na pozice závislé) akce, z toho jehromada nových možností kam může dojít. Najděte je.
71
![Page 93: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/93.jpg)
directionsAt :: Location → [Direction]
go :: Direction→ Location→ LocationactionsAt :: Location → [Action]
act :: Action→ Location → Location
possibleResults :: Location→ [Location]
possibleResults loc = concat $
map (λdir → let newloc = go dir locin map (λaction→ act action newloc)
(actionsAt newloc))
(directionsAt loc)
...hm.
72
![Page 94: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/94.jpg)
directionsAt :: Location → [Direction]
go :: Direction→ Location→ LocationactionsAt :: Location → [Action]
act :: Action→ Location → Location
possibleResults :: Location→ [Location]
possibleResults loc = concat $
map (λdir → let newloc = go dir locin map (λaction→ act action newloc)
(actionsAt newloc))
(directionsAt loc)
...hm.72
![Page 95: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/95.jpg)
withTheseCases
withTheseCases :: [a]→ (a→ [b])→ [b]
withTheseCases a f = concat (map f a)
infixr 2 ‘withTheseCases‘
possibleResults loc =
directionsAt loc ‘withTheseCases‘ λdir →let newloc = go dir locin actionsAt newloc ‘withTheseCases‘ λaction→
[act action newloc ]
(poslední řádek vrací jednu možnost)
73
![Page 96: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/96.jpg)
withTheseCases
withTheseCases :: [a]→ (a→ [b])→ [b]
withTheseCases a f = concat (map f a)
infixr 2 ‘withTheseCases‘
possibleResults loc =
directionsAt loc ‘withTheseCases‘ λdir →let newloc = go dir locin actionsAt newloc ‘withTheseCases‘ λaction→
[act action newloc ]
(poslední řádek vrací jednu možnost)
73
![Page 97: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/97.jpg)
Generické andThen
andThen :: Maybe a→ (a→ Maybe b)→ Maybe bwithTheseCases :: [a]→ (a→ [b])→ [b]
($) :: (a→ b)→ ( a→ b)
fmap :: Functor f ⇒ (a→ b)→ (f a→ f b)
(〈∗〉) :: Applicative f ⇒ f (a→ b)→ (f a→ f b)
flip (>>=) :: Monad m ⇒ (a→ m b)→ (m a→ m b)
Generické andThen awithCases se jmenuje (>>=), čte se “bind”.
74
![Page 98: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/98.jpg)
Generické andThen
andThen :: Maybe a→ (a→ Maybe b)→ Maybe bwithTheseCases :: [a]→ (a→ [b])→ [b]
($) :: (a→ b)→ ( a→ b)
fmap :: Functor f ⇒ (a→ b)→ (f a→ f b)
(〈∗〉) :: Applicative f ⇒ f (a→ b)→ (f a→ f b)
flip (>>=) :: Monad m ⇒ (a→ m b)→ (m a→ m b)
Generické andThen awithCases se jmenuje (>>=), čte se “bind”.
74
![Page 99: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/99.jpg)
Monády
Jméno: Aplikativní monoid (skoro).
class Applicative m⇒ Monad m where(>>=) :: m a→ (a→ m b)→ m b(>>) :: m a→ m b→ m breturn :: a→ m a
(>>) zahodí ‘výsledek’, zachová jen změny v ‘obalu’.
75
![Page 100: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/100.jpg)
Monády alternativně
join :: Monad m⇒ m (m a)→ m a
V rozumných případech platí:
(a>>= f) ≡ join (f 〈$〉 a)
Pozn.: chování joinu pro seznamy a Maybe:
joinL :: [[a]]→ [a]
joinL = concatjoinMaybe :: Maybe (Maybe a)→ Maybe ajoinMaybe (Just x) = xjoinMaybe = Nothing
76
![Page 101: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/101.jpg)
Rozumné monády
return a>>= f ≡ f a
a>>= return ≡ a
a>>= (λx→ b x >>= c) ≡ (a>>= b)>>= c
76
![Page 102: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/102.jpg)
Imperativní syntax
Protože používat>>= a>> je otrava, Haskell má imperativní do-syntax.
fn = do a← fb← gh a bh b a
...se přepíše na:
fn = f >>= λa→g >>= λb→h a b>>h b a
77
![Page 103: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/103.jpg)
Imperativní syntax
lookup4 a l =
do a← lookup a la← lookup a la← lookup a la← lookup a lreturn a
possibleResults loc =
do dir ← directionsAt loclet newloc = go dir locaction← actionsAt newlocreturn $ act action newloc
78
![Page 104: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/104.jpg)
Philip Lee Wadler
The Lambdaman
78
![Page 105: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/105.jpg)
Philip Lee Wadler
The Lambdaman
78
![Page 106: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/106.jpg)
List comprehension
Speciální syntaxe pro seznamy:
possibleResults loc =
[act action newloc | dir ← directionsAt loc,let newloc = go dir loc,action← actionsAt newloc ]
Jednodušší použití:
[(x, y) | x← [1 . .], y ← [1 . . x ], x ‘mod‘ y ≡ 0]
map′ f l = [f a | a← l]filter′ f l = [a | a← l, f a]
(“podmínky” se automaticky obalí pomocí guard)
79
![Page 107: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/107.jpg)
Standardní definice Monad Maybe
instance Functor Maybe wherefmap f (Just x) = Just (f x)
fmap Nothing = Nothinginstance Applicative Maybe wherepure = JustJust f 〈∗〉 Just a = Just (f a)
〈∗〉 = Nothinginstance Monad Maybe wherereturn = pureJust a>>= f = f a>>= = Nothing
80
![Page 108: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/108.jpg)
Standardní definice Monad []
instance Functor [ ] wherefmap = map
instance Applicative [ ] wherepure x = [x ]
fs 〈∗〉 as = concatMap (flip map as) fsinstance Monad [ ] wherereturn = pureas>>= f = concatMap f as
81
![Page 109: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/109.jpg)
Extra příklad: DebugLog
Zapišme si postup výpočtu do logu k hodnotě.
data Val a = Val a String deriving ShowliftVal1 op str (Val a logA) = Val (op a)
(str ++ "(" ++ logA ++ ")")
liftVal2 op str (Val a logA) (Val b logB) =
Val (a ‘op‘ b) $ concat ["(", logA, ")", str, "(", logB, ")"]
instance (Num a, Show a)⇒ Num (Val a) where(+) = liftVal2 (+) "+"(−) = liftVal2 (−) "-"(∗) = liftVal2 (∗) "*"negate = liftVal1 negate "negate"abs = liftVal1 abs "abs"fromInteger x = Val (fromInteger x) (show x)
82
![Page 110: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/110.jpg)
Extra příklad: DebugLog
(1 + abs (2 ∗ negate 3)) :: Val Int; Val 7 "(1)+(abs((2)*(negate(3))))"
Celý výpočet ale většinou není na jeden řádek...
83
![Page 111: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/111.jpg)
Extra příklad: DebugLog
instance Functor Val wherefmap f (Val a log) = Val (f a) log
instance Applicative Val wherepure a = Val a "?"Val f logF 〈∗〉 Val a logA =
Val (f a) $ concat ["(", logF, ") (", logA, ")"]
instance Monad Val wherereturn = pureVal a logA>>= f =
let Val b logB = f ain Val b (logA ++ ";\n" ++ logB)
mkVal a = Val a (show a)
nameVal n (Val a log) = Val (Val a n) $ n ++ "=" ++ log
84
![Page 112: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/112.jpg)
Extra příklad: DebugLog
solve a′ b′ c′ = dolet a = mkVal a′
b = mkVal b′
c = mkVal c′
d← nameVal "D" $ b∧2− 4 ∗ a ∗ c(−b + sqrt d) / (2 ∗ a)
solve 5 3 (−10)
; Val 1.145683229480096"D=((3.0)*(3.0))-(((4)*(5.0))*(-10.0));((negate(3.0))+(odmocnina(D)))/((2)*(5.0))"
(instanci pro Fractional a Floating někdo doplnil)
85
![Page 113: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/113.jpg)
IO Flashback
putStrLn :: String→ IO ()
getLine :: IO Stringmain :: IO ()
main = do putStrLn "dej jmeno!"jmeno← getLineputStrLn $"no nazdar je tady "++ jmeno
85
![Page 114: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/114.jpg)
Jak se vyrobí IO?
Myšlenka: IO akce musí přece manipulovat s nějakým globálním stavem!Vyrobíme monádu, která ukládá stav, na ní pak půjde stavět dál.
Požadavky:
• put :: s→ m ()
• get :: m s• tohle vrátí True:
do put ab← getreturn $ a ≡ b
86
![Page 115: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/115.jpg)
Změna stavu bez vedlejšího efektu
imperativnífunkce
stav
výsledek
čistáfunkce
stav
stav výsledek
87
![Page 116: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/116.jpg)
State
newtype State s a =
StateChangeWithResult (s→ (s, a))
S.C.W.R.
s
s a
87
![Page 117: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/117.jpg)
Stavový výpočet je kontejner!
instance Functor (State s) where
change
s
s
fmap g change =
g (x :: a) :: b
88
![Page 118: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/118.jpg)
Stavový výpočet je aplikativní!
instance Applicative (State s) where
x :: a→ b
y :: a
s
s
x 〈∗〉 y =
(x :: a→ b) (y :: a) :: b
89
![Page 119: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/119.jpg)
Stavový výpočet je monáda!
instance Monad (State s) where
x
f
y
s
s
x >>= f =
b
as
90
![Page 120: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/120.jpg)
Implementace State
newtype State s a = StateChange (s→ (s, a))
instance Functor (State s) wherefmap func (StateChange f) =
StateChange (fmap func · f)instance Applicative (State s) wherepure a = StateChange (λs→ (s, a))
StateChange f 〈∗〉 StateChange v =
StateChange (λs→ let (s1, a1) = f s(s2, a2) = v s1
in (s2, a1 a2))
91
![Page 121: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/121.jpg)
Implementace State
instance Monad (State s) wherereturn = pureStateChange f1>>= f2 =
StateChange (λs→ let (s′, a) = f1 sStateChange f3 = f2 a
in f3 s′)
92
![Page 122: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/122.jpg)
Manipulace stavu
put :: s→ State s ()
put ns = StateChange (\_→ (ns, ()))
get :: State s sget = StateChange (λs→ (s, s))
modify :: (s→ s)→ State s ()
modify f = StateChange (λs→ (f s, ()))
execState (StateChange f) s = snd $ f s
93
![Page 123: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/123.jpg)
Použití State
fact n = execState (factS n) 1
factS n| n 6 1 = do result← get
return result| otherwise = do modify (∗n)
factS (n− 1)
getRand :: Int→ State Int IntgetRand max =
do newSeed← (12345+) · (1103515245∗) 〈$〉 getput newSeedreturn $ (newSeed ‘div‘ 65536) ‘mod‘ max
(viz. man 3 rand)
94
![Page 124: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/124.jpg)
Použití State jako Applicative
get2Rand max = (, ) 〈$〉 getRand max 〈∗〉 getRand max
getNRand max 0 = pure [ ]
getNRand max n = (:) 〈$〉 getRand max〈∗〉 getNRand max (n− 1)
getNRand′ max n = mapM (\_→ getRand max) [1 . . n]
getNRand′′ max n = traverse (const $ getRand max) [1 . . n]
getNRand′′′ max n = replicateM n $ getRand max
getNRand′′′′ = flip replicateM · getRand
95
![Page 125: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/125.jpg)
Použití State jako Applicative
get2Rand max = (, ) 〈$〉 getRand max 〈∗〉 getRand max
getNRand max 0 = pure [ ]
getNRand max n = (:) 〈$〉 getRand max〈∗〉 getNRand max (n− 1)
getNRand′ max n = mapM (\_→ getRand max) [1 . . n]
getNRand′′ max n = traverse (const $ getRand max) [1 . . n]
getNRand′′′ max n = replicateM n $ getRand max
getNRand′′′′ = flip replicateM · getRand
95
![Page 126: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/126.jpg)
Použití State jako Applicative
get2Rand max = (, ) 〈$〉 getRand max 〈∗〉 getRand max
getNRand max 0 = pure [ ]
getNRand max n = (:) 〈$〉 getRand max〈∗〉 getNRand max (n− 1)
getNRand′ max n = mapM (\_→ getRand max) [1 . . n]
getNRand′′ max n = traverse (const $ getRand max) [1 . . n]
getNRand′′′ max n = replicateM n $ getRand max
getNRand′′′′ = flip replicateM · getRand
95
![Page 127: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/127.jpg)
Použití State jako Applicative
get2Rand max = (, ) 〈$〉 getRand max 〈∗〉 getRand max
getNRand max 0 = pure [ ]
getNRand max n = (:) 〈$〉 getRand max〈∗〉 getNRand max (n− 1)
getNRand′ max n = mapM (\_→ getRand max) [1 . . n]
getNRand′′ max n = traverse (const $ getRand max) [1 . . n]
getNRand′′′ max n = replicateM n $ getRand max
getNRand′′′′ = flip replicateM · getRand
95
![Page 128: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/128.jpg)
Použití State jako Applicative
get2Rand max = (, ) 〈$〉 getRand max 〈∗〉 getRand max
getNRand max 0 = pure [ ]
getNRand max n = (:) 〈$〉 getRand max〈∗〉 getNRand max (n− 1)
getNRand′ max n = mapM (\_→ getRand max) [1 . . n]
getNRand′′ max n = traverse (const $ getRand max) [1 . . n]
getNRand′′′ max n = replicateM n $ getRand max
getNRand′′′′ = flip replicateM · getRand 95
![Page 129: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/129.jpg)
Pravda o IO
$ ghciGHCi, version 8.2.2: http://www.haskell.org/ghc/Prelude> :i IOnewtype IO a
= GHC.Types.IO(GHC.Prim.State# GHC.Prim.RealWorld
-> (# GHC.Prim.State# GHC.Prim.RealWorld, a #))
96
![Page 130: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/130.jpg)
Kolik paměti spotřebuje uložení RealWorld?
Je to jen “token” typu Void.
96
![Page 131: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/131.jpg)
Kolik paměti spotřebuje uložení RealWorld?
Je to jen “token” typu Void.
96
![Page 132: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/132.jpg)
Praxe s monádami: Parsovací kombinátory
![Page 133: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/133.jpg)
Jak funguje obyčejný left-to-right rekurzivní parser?
• postupně vytváří parsovanou strukturu (lazy!)• pamatuje si místo, kde přestal parsovat (“zbytek”)
Idea parsovacích kombinátorů:
newtype Parser r = Parser (State Pozice r)
97
![Page 134: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/134.jpg)
97
![Page 135: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/135.jpg)
Parsec demo
Kam se chceme dostat:
parenthesized x = do char ’(’res← xchar ’)’return res
numberOrWordOrBoth = number 〈|〉 word 〈|〉 (number >> word)
parseNum :: (Num a,Read a)⇒ Parser aparseNum = (read 〈$〉many1 parseDigit)
〈|〉 do char ’-’negate · read 〈$〉many1 parseDigit
98
![Page 136: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/136.jpg)
Alternative
Alternative obsahuje ‘prázdný’ prvek a operaci na slepování výpočtů(podobně jakoMonoid slepuje hodnoty).
Sémantika: Pokud může výpočet dopadnout více možnostmi, Alternativeumožňuje specifikovat další možnosti. Pokud některá větev výpočtu selže,použije se jiná.
class Applicative f ⇒ Alternative f whereempty :: f a(〈|〉) :: f a→ f a→ f a
Užitečné instance: Maybe, [ ], Validation, Except, . . . , Parser r
99
![Page 137: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/137.jpg)
Implementace jednoduchého parseru
newtype Parser a = Parser (State String (Maybe a))
instance Functor Parser wherefmap f (Parser s) = Parser $ fmap (fmap f) s
instance Applicative Parser wherepure a = Parser · pure · pure $ aParser l 〈∗〉 Parser r = Parser $ doa← lcase a ofNothing→ pure NothingJust f → fmap (fmap f) r
100
![Page 138: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/138.jpg)
Implementace jednoduchého parseru
instance Monad Parser wherereturn = pureParser l>>= p =
Parser $ do a← lcase a ofNothing→ return NothingJust a→ let Parser r = p a in r
101
![Page 139: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/139.jpg)
Implementace jednoduchého parseru
instance Alternative Parser whereempty = Parser $ pure emptyParser l 〈|〉 Parser r =
Parser $ do backup← getl′ ← lcase l′ ofNothing→ put backup>> ra→ return a
102
![Page 140: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/140.jpg)
Pomůcky
parseFail = emptyparseGet = Parser $ Just 〈$〉 getparseSet s = Parser $ Just 〈$〉 put spEof = do s← parseGet
case s of""→ return ()
→ parseFaildoParse (Parser p) = runState pdoParseEof p = fst · doParse (p>>= λr → pEof >> return r)
103
![Page 141: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/141.jpg)
Pomůcky
pAny = do s← parseGetcase s of
(i : ss)→ parseSet ss>> return i→ parseFail
pCharCond f = pAny >>= λc→ if f c then return celse parseFail
pOneOf cs = pCharCond (∈ cs)pAnyExcept cs = pCharCond $ ¬ · (∈ cs)pChar c = pCharCond (≡ c)pStr s = mapM pChar s
104
![Page 142: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/142.jpg)
Kombinátory
pMany1 p = do x← pxs← pMany preturn (x : xs)
pMany p = pMany1 p 〈|〉 pure [ ]
pBracketed l r p = do lres← prreturn res
pDelim l r = pBracketed (pStr l) (pStr r)pBrackets = pDelim "[" "]"pBraces = pDelim "{" "}"
pQuoted q = pDelim q q · pMany $ pAnyExcept q
105
![Page 143: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/143.jpg)
Sekvence s oddělovačem
infixr 4 〈:〉a 〈:〉 b = (:) 〈$〉 a 〈∗〉 bpSep1 sep p = p 〈:〉 (sep>> pSep1 sep p)
〈|〉(:[ ]) 〈$〉 p -- also: fmap pure p
pSep sep p = pSep1 sep p 〈|〉 pure [ ]
pCommaDelimited = pSep (pChar ’,’)
106
![Page 144: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/144.jpg)
Parser JSONu!
data JSON = JSInt Int| JSStr String| JSList [ JSON]
| JSObj [(String, JSON)]
pJSON = pJSInt 〈|〉 pJSStr 〈|〉 pJSList 〈|〉 pJSObjpJSInt = JSInt · (read :: String→ Int)
〈$〉 pMany1 (pOneOf [’0’ . . ’9’])
pJSStr = JSStr 〈$〉 (pQuoted "\"" 〈|〉 pQuoted "’")
pJSList = JSList 〈$〉 pBrackets (pCommaDelimited pJSON)
pJSObj = JSObj 〈$〉 pBraces (pCommaDelimited objItem)
where objItem = do JSStr key ← pJSStrpChar ’:’((, ) key) 〈$〉 pJSON
107
![Page 145: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/145.jpg)
Jak na whitespace?
import Data.Charwhitespace = pMany $ pCharCond isSpacelexeme = (whitespace>>)
108
![Page 146: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/146.jpg)
Dostupné knihovny
Balíček parsec je původní implementace, obsahuje většinu zmíněnýchkombinátorů.
import Text.Parsec.String (Parser)import Text.Parsec.Charimport Text.Parsec (try)
import Text.Parsec.Combinator (between, eof,many)
try se používá pro backtrackování:
• v některých případech backtrackovat není vhodné (např. při zotavení zchyb)
• zbytečné referencování pozice není úplně úsporné
try (char ’a’) 〈|〉 char ’b’
109
![Page 147: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/147.jpg)
Dostupné knihovny
Megaparsec — novější varianta Parsecu:
• lepší chybové hlášky (unexpected vs. expected, kumulované chyby)• rychlejší zpracování• hromada utilit• parsování Streamů
Attoparsec — miniaturní varianta
• méně featur• víc rychlosti díky specializaci na ByteStringy
(rychlost je porovnatelná s ručně optimalizovanými parsery v C)
110
![Page 148: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/148.jpg)
Balíčky a knihovny
![Page 149: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/149.jpg)
Oddělený překlad
Překládat programy celé najednou je poměrně náročné
• něco to trvá• spotřebuje to hodně paměti• exploze složitosti při optimalizaci
Tradiční řešení: oddělený překlad po modulech
111
![Page 150: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/150.jpg)
Oddělený překlad
.hs
.hi .o
.hs
.hi .o
.hs
.hs-boot
.hi .o
.olibHSrts.a exe
112
![Page 151: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/151.jpg)
Oddělený překlad
.hs
.hi .o
.hs
.hi .o
.hs
.hs-boot
.hi .o
.olibHSrts.a exe
112
![Page 152: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/152.jpg)
Oddělený překlad
.hs
.hi .o
.hs
.hi .o
.hs
.hs-boot
.hi .o
.olibHSrts.a exe
112
![Page 153: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/153.jpg)
Oddělený překlad
.hs
.hi .o
.hs
.hi .o
.hs
.hs-boot
.hi .o
.olibHSrts.a exe
112
![Page 154: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/154.jpg)
Jak importovat?
Import z modulu:
import Data.Listimport qualified Data.List as Limport Data.List (nub)
import Data.List hiding (nub)
Modul:
module Data.List where
(jméno souboru a cesta k modulu si musí odpovídat)
113
![Page 155: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/155.jpg)
Balíčky a cesty
GHC vnímá koncept balíků, tyto je možné libovolně přidávat do balíkůdostupných při kompilaci.
Nástroj ghc-pkg:
• list, find-module module, describe pkg
• expose pkg, hide pkg
• register filename, unregister pkg, update filenameza filename se dosadí cesta ke konfiguračnímu souboru sestavenéhobalíku.
Je možné mít několik databází balíků (např. systémovou a lokálníuživatelskou).
114
![Page 156: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/156.jpg)
cabal
cabal je systém na jednoduché vytváření, sestavování, distribuci a instalacibalíčků a jejich závislostí.
Idea:
• Z každého samostatnějšího kusu software uděláme balíček!• dostane jméno• popíšeme závislosti
• Použijeme cabal na výrobu balíku!• sestavení• rozumná instalace a registrace pro ghc
• Balíček pěkně zabalíme a pošleme ostatním!• Hackage the haskell package database
• Stáhneme, sestavíme a nainstalujeme si i balíčky ostatních!• cabalem z Hackage
115
![Page 157: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/157.jpg)
balik.cabal
name: balikversion: 0.1.0.0synopsis: Venkovsky Baliklicense: AGPL-3license-file: LICENSEauthor: Jozefmaintainer: [email protected]: Webbuild-type: Simpleextra-source-files: ChangeLog.mdcabal-version: >=1.10
executable balikmain-is: Main.hsbuild-depends:
base >=4.9,aeson,scotty,SHA,network,utf8-string
hs-source-dirs: src
116
![Page 158: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/158.jpg)
balik.cabal
executable balikmain-is: Main.hsbuild-depends:
base >=4.9,aeson,scotty,SHA,network,utf8-string
hs-source-dirs: src
117
![Page 159: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/159.jpg)
cabal crash-course
Stáhneme databázi dostupných balíků:cabal update
Něco nainstalujeme a zaregistrujeme to do aktuálně dostupného ghc:cabal install acme-schoenfinkel
cabal info acme-schoenfinkelcabal list
118
![Page 160: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/160.jpg)
cabal crash-course
Stáhneme databázi dostupných balíků:cabal update
Něco nainstalujeme a zaregistrujeme to do aktuálně dostupného ghc:cabal install acme-schoenfinkelcabal info acme-schoenfinkelcabal list
118
![Page 161: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/161.jpg)
cabal crash-course
Oddělené prostředí se občas hodí:
cabal sandbox initcabal execcabal repl
119
![Page 162: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/162.jpg)
cabal crash-course
Co když chceme cabal použít k výrobě nového balíku?
cd balikcabal init ...vyplněním interaktivního formuláře vzniknebalik.cabal
Instalace závislostí:cabal install --only-dependencies
Sestavení:cabal build
Spuštění:cabal run
Instalace do aktuálního prostředí:cabal install
120
![Page 163: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/163.jpg)
cabal crash-course
Vyrobení HTML/TeX dokumentace:cabal haddock
Vysázení pěkně barevného kódu pro publikaci:cabal hscolour
Řešení některých odporných závislostních stromů:cabal new-build, cabal new-install, cabal new-run, ...
121
![Page 164: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/164.jpg)
cabal crash-course
Publikování balíku:cabal check ...kontrola na běžné potížecabal sdist ...vyrobení .tar.gz balíku na manuální distribucicabal upload ...upload na Hackage
122
![Page 165: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/165.jpg)
Jak se nestydět za publikovaný balík?
cabal install hlint
cabal install hindent
cabal check
122
![Page 166: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/166.jpg)
stack
stack je zamražovač závislostí pro Haskell.
123
![Page 167: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/167.jpg)
stack
stack je zamražovač závislostí pro Haskell.
123
![Page 168: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/168.jpg)
stack
Hlavní výhody stacku:
• vlastní hackage (Stackage)• balíky a závislosti jsou pravidelně testované na kompatibilitu• většinou to částečně pomáhá
• v případě děsivých setupů se dá ušetřit dost času
Pravidla:
• Cabal balík: 0–1 knihoven, 0–N programů• popsáno v balik.cabal
• Stack projekt: 0–N cabalích balíků• projekt a celé zmražené prostředí popsáno v stack.yaml• metainformace balíku (tj. obsah generovaných cabalových souborů) vpackage.yaml
• soubory .cabal stack generuje automaticky a nejde je měnit
124
![Page 169: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/169.jpg)
stack
Cizí balík:
• cd balik ...adresář obsahuje stack.yaml• stack setup
• stack build ...většinou stáhne správné GHC apod.• stack exec nazevprogramu
Vlastní balík:
• stack new nazevbaliku new-template
• stack test ...spustí testy• stack repl ...spustí ghci ve zamraženém prostředí
125
![Page 170: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/170.jpg)
stack
Obecná rada: Pokud stack chcete použít pro svůj další projekt, nejspíšděláte něco špatně.
Proč stack nepoužívat:
• dostatečný, standardnější a spolehlivější nástroj na sestavování balíčkůje cabal
• stack plýtvá zdroji• stack třepí ekosystém• výsledek je sice ‘přenositelný’, ale špatně udržovatelný• způsob instalace stacku je podivný
126
![Page 171: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/171.jpg)
stack
Kdy stack asi budete muset použít?
• program má 9701734347576 závislostí a při změně libovolné se rozbije• program je kritická součást nějaké infrastruktury, jejíž admin nechápe
balíčky• programátor neumí nebo nechápe UNIX• programátor nemá čas nebo neumí udělat validní balíček• velitel rozhodl• cílový operační systém je podměrečný• skočili jste časem do doby před vznikem cabal new-build
127
![Page 172: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/172.jpg)
Tour de Prelude
![Page 173: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/173.jpg)
Než začneme s čímkoliv větším, hodí se mít přehled o běžně používanýchkonstrukcích a knihovních funkcích:
• Prelude• System.IO• Control.Monad
128
![Page 174: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/174.jpg)
Prelude
Prelude je ‘základ’ defaultně importovaný do všech modulů.
Obsahuje:
• standardní typy, typové třídy, související funkce a operátory• základní věci pro práci s monádami• základní IO
129
![Page 175: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/175.jpg)
Výběr ze Prelude — IO
getLine, getContents :: IO StringgetChar :: IO CharreadFile :: FilePath→ IO StringputChar :: Char → IO ()
putStr, putStrLn :: String→ IO ()
writeFile, appendFile :: FilePath→ String→ IO ()
readLn :: Read a⇒ IO aprint :: Show a⇒ a→ IO ()
interact :: (String→ String)→ IO ()
130
![Page 176: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/176.jpg)
Výběr ze Prelude — seznamy
head, last :: [a]→ atail, init :: [a]→ [a]
(++) :: [a]→ [a]→ [a]
(!!) :: [a]→ Int→ aelem :: [a]→ a→ Boollength :: [a]→ Inttake, drop :: Int→ [a]→ [a]
takeWhile, dropWhile :: (a→ Bool)→ [a]→ [a]
lines,words :: String→ [String ]
unlines, unwords :: [String ]→ String
131
![Page 177: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/177.jpg)
Výběr ze Prelude — seznamy
map :: (a→ b)→ [a]→ [b]
filter :: (a→ Bool)→ [a]→ [a]
foldl :: (a→ x→ a)→ a→ [x ]→ afoldr :: (x→ a→ a)→ a→ [x ]→ ascanl :: (a→ x→ a)→ a→ [x ]→ [a]
scanr :: (x→ a→ a)→ a→ [x ]→ [a]
lookup :: Eq a⇒ a→ [(a, b)]→ Maybe breverse :: [a]→ [a]
replicate :: Int→ a→ [a]
repeat :: a→ [a]
cycle :: [a]→ [a]
iterate :: (a→ a)→ a→ [a]
132
![Page 178: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/178.jpg)
Výběr z Prelude — chyby
fail :: Monad m⇒ String→ m aerror :: [Char ]→ aioError :: IOError → IO auserError :: String→ IOError
fail je pozůstatek z původní definice monád, v některých případech se chovározumně (např. fail vMaybe jeNothing). ioError je pěkný fail pro IO.
error je jako⊥ s chybovou hláškou navíc.
N.B. Existuje sémantický rozdíl mezi chybou (selháním programu) avýjimkou (situací, kterou programátor očekával, ale rozhodl se ji rozumněošetřit podobně jako selhání).
133
![Page 179: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/179.jpg)
Control.Exception
Chytání výjimek:
import System.IO.ErrorcatchIOError :: IO a→ (IOError → IO a)→ IO atryIOError :: IO a→ IO (Either IOError a)
Generičtější:
import Control.Exceptionthrow :: Exception e⇒ e→ acatch :: Exception e⇒ IO a→ (e→ IO a)→ IO atry :: Exception e⇒ IO a→ IO (Either e a)
134
![Page 180: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/180.jpg)
Bracket pattern
Bracket zachycuje sémantiku vyrobení a odstranění zdroje:
bracket :: IO a→ (a→ IO b)→ (a→ IO c)→ IO cbracket_ :: IO a→ IO b→ IO c→ IO c
Typicky: bracket openTheFile closeTheFile processTheFile
Podobně:
bracketOnError :: IO a→ (a→ IO b)→ (a→ IO c)→ IO cfinally :: IO a→ IO b→ IO aonException :: IO a→ IO b→ IO a
135
![Page 181: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/181.jpg)
Soubory
V Haskellu se soubory drží zaHandle.
import System.IOopenFile :: FilePath→ IOMode→ IO HandlehClose :: Handle→ IO ()
withFile :: FilePath→ IOMode→ (Handle→ IO r)→ IO r
Ostatní IO funkce mají varianty sHandle:
hFileSize, hIsEOF, hFlush, hSeek, hTell, hReady, hGetChar,hGetContents, hGetLine, hPutChar, hPutStr, hPutStrLn, hPrint, ...
136
![Page 182: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/182.jpg)
Monády
IO je normální monáda, takže jde zpracovávat monadickými kombinátory:
import Control.MonadmapM :: (Monad m, Traversable t)⇒ (a→ m b)→ t a→ m (t b)
mapM_ :: (Monad m, Foldable t)⇒ (a→ m b)→ t a→ m ()
sequence :: (Monad m, Traversable t)⇒ t (m a)→ m (t a)
forever :: Applicative f ⇒ f a→ f b
Pozn.:
• podobně: zipWithM, replicateM, foldM, sequence_• forM a forM_ je otočenýmapM• Na dost věcí stačí aplikativní interface — pokud je to možné, používejtetraverse.
137
![Page 183: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/183.jpg)
Kontejnery
![Page 184: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/184.jpg)
Přehled
• Foldable & Traversable• Maybe, Either, List• Tree• Sequence• Array & Vector• Graph• Set, Map• IntSet, IntMap
138
![Page 185: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/185.jpg)
Data.Foldable
class Foldable (t :: ∗ → ∗) whereData.Foldable.fold :: Monoid m⇒ t m→ mfoldMap :: Monoid m⇒ (a→ m)→ t a→ mfoldr, foldr′ :: (a→ b→ b)→ b→ t a→ bfoldl, foldl′ :: (b→ a→ b)→ b→ t a→ bfoldr1, foldl1 :: (a→ a→ a)→ t a→ aData.Foldable.toList :: t a→ [a]
null :: t a→ Boollength :: t a→ Intelem :: Eq a⇒ a→ t a→ Boolmaximum,minimum :: Ord a⇒ t a→ asum, product :: Num a⇒ t a→ a
Utils: and, or, all, any, foldlM, foldrM, length139
![Page 186: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/186.jpg)
Data.Foldable
Používejte buď foldl′ nebo foldr!
foldl občas (často) spotřebuje prekvapivě hodně paměti.
139
![Page 187: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/187.jpg)
139
![Page 188: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/188.jpg)
Data.Traversable
class (Functor t, Foldable t)⇒ Traversable t wheretraverse :: Applicative f ⇒ (a→ f b)→ t a→ f (t b)
sequenceA :: Applicative f ⇒ t (f a)→ f (t a)
mapM :: Monad m⇒ (a→ m b)→ t a→ m (t b)
sequence :: Monad m⇒ t (m a)→ m (t a)
Podobné: traverse_, sequence_,mapM_, forM,mapAccumL,mapAccumR
140
![Page 189: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/189.jpg)
Data.Maybe
fromMaybe :: a→ Maybe a→ afromJust :: Maybe a→ amaybe :: b→ (a→ b)→ Maybe a→ bisJust :: Maybe a→ BoolisNothing :: Maybe a→ BoollistToMaybe :: [a]→ Maybe amaybeToList :: Maybe a→ [a]
mapMaybe :: (a→ Maybe b)→ [a]→ [b]
catMaybes :: [Maybe a]→ [a]
141
![Page 190: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/190.jpg)
Data.Either
either :: (a→ c)→ (b→ c)→ Either a b→ cfromLeft :: a→ Either a b→ afromRight :: b→ Either a b→ bisLeft :: Either a b→ BoolisRight :: Either a b→ Boollefts :: [Either a b]→ [a]
rights :: [Either a b]→ [b]
partitionEithers :: [Either a b]→ ([a], [b])
142
![Page 191: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/191.jpg)
Data.List
cycle :: [a]→ [a]
repeat :: a→ [a]
replicate :: Int→ a→ [a]
intersperse :: a→ [a]→ [a]
intercalate :: [a]→ [[a]]→ [a]
group :: Eq a⇒ [a]→ [[a]]
nub :: Eq a⇒ [a]→ [a]
inits :: [a]→ [[a]]
tails :: [a]→ [[a]]
sort :: Ord a⇒ [a]→ [a]
sortBy :: (a→ a→ Ordering)→ [a]→ [a]
sortOn :: Ord b⇒ (a→ b)→ [a]→ [a]
143
![Page 192: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/192.jpg)
Data.Tree
data Tree a = Node {rootLabel :: a, subForest :: Forest a}type Forest a = [Tree a]
drawTree :: Tree String→ StringdrawForest :: Forest String→ Stringlevels :: Tree a→ [[a]]
flatten :: Tree a→ [a]
foldTree :: (a→ [b]→ b)→ Tree a→ bunfoldTree :: (b→ (a, [b]))→ b→ Tree a
144
![Page 193: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/193.jpg)
Data.Sequence
Sekvence je lepší seznam:
• indexování vO(log n)
• přístup k oběma koncům• většina ne-globálních operací amortizovaně meziO(1) ažO(log n)
Operace navíc:
(< |) :: a→ Seq a→ Seq a -- přidávání prvku na konec(| >) :: Seq a→ a→ Seq adata ViewL a = EmptyL | a :< (Seq a)
viewl :: Seq a→ ViewL aviewr :: Seq a→ ViewR a(><) :: Seq a→ Seq a→ Seq a --O(log n) concat
145
![Page 194: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/194.jpg)
Data.Array
Arraye mají indexy:
class Ord a⇒ Ix a whererange :: (a, a)→ [a]
index :: (a, a)→ a→ IntinRange :: (a, a)→ a→ BoolrangeSize :: (a, a)→ Int
Typ arraye: Array idx a
Přístup do arraye podle indexu jeO(1). Implementace je vestavěná v GHC,modelovaná jako funkce s omezenou kontinuální celočíselnou doménou.
146
![Page 195: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/195.jpg)
Data.Array
array :: Ix i⇒ (i, i)→ [(i, e)]→ Array i elistArray :: Ix i⇒ (i, i)→ [e]→ Array i eassocs :: Ix i⇒ Array i e→ [(i, e)]
bounds :: Array i e→ (i, i)elems :: Array i e→ [e]
(!) :: Ix i⇒ Array i e→ i→ e(//) :: Ix i⇒ Array i e→ [(i, e)]→ Array i eixmap :: (Ix j, Ix i)⇒
(i, i)→ (i→ j)→ Array j e→ Array i e
147
![Page 196: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/196.jpg)
Data.Vector
Vektory jsou arraye obalené trochu lepším API. Vyhledání prvku podleindexu jeO(1), index je Int, a indexy začínají od nuly.
Operace podobné jako u arrayí:
length :: Vector a→ Int(!) :: Vector a→ Int→ a(!?) :: Vector a→ Int→ Maybe aunsafeIndex :: Vector a→ Int→ a -- rychlejší varianty s UB!unsafeHead :: Vector a→ aunsafeLast :: Vector a→ aimap :: (Int→ a→ b)→ Vector a→ Vector b(//) :: Vector a→ [(Int, a)]→ Vector aupdate :: Vector a→ Vector (Int, a)→ Vector aupdate_ :: Vector a→ Vector Int→ Vector a→ Vector a 148
![Page 197: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/197.jpg)
Data.Vector.Mutable
Občas se hodí do pole smět náhodně chaoticky zapisovat. U immutablevektorů je ale výměna jednoho prvkuO(n).
MVector s a si uchovává implicitní stav v monádě s (např. IO, ST), zápis dovektoru je vO(1).
new :: PrimMonad m ⇒ Int → m (MVector (PrimState m) a){-unsafeNew neinicializuje paměť! :) -}
clone :: PrimMonad m ⇒MVector (PrimState m) a → m (MVector (PrimState m) a)
read :: PrimMonad m ⇒MVector (PrimState m) a → Int → m a
write :: PrimMonad m ⇒MVector (PrimState m) a → Int → a → m ()
modify :: PrimMonad m ⇒MVector (PrimState m) a → (a → a) → Int → m ()
swap :: PrimMonad m ⇒MVector (PrimState m) a → Int → Int → m () 149
![Page 198: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/198.jpg)
import Control.Monad.Primitiveimport Control.Monadimport qualified Data.Vector.Mutable as Vbublsort mv = let size = V.length mv inforM_ [0 . . size− 1] $ \_→ forM_ [0 . . size− 2] $ λi→ do
[ left, right ]← mapM (V.read mv) [ i, i + 1]
unless (left 6 right) $ V.swap mv i (i + 1)
demoVector = do v ← V.new 5 :: V.IOVector IntzipWithM (V.write v) [0 . .] [5, 3, 2, 5, 1]
return vprintV v = forM_ [0 . .V.length v − 1] $ (>>=print) · V.read vmain = do v ← demoVector
bublsort vprintV v
150
![Page 199: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/199.jpg)
Data.Graph
type Vertex = Inttype Edge = (Vertex,Vertex)
type Bounds = (Vertex,Vertex)
type Table a = Array Vertex abuildG :: Bounds→ [Edge]→ Graphvertices :: Graph→ [Vertex ]
edges :: Graph→ [Edge]
indegree :: Graph→ Table Intoutdegree :: Graph→ Table Intpath :: Graph→ Vertex→ Vertex→ Boolreachable :: Graph→ Vertex→ [Vertex ]
components :: Graph→ Forest Vertex
151
![Page 200: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/200.jpg)
Data.Graph
graphFromEdges :: Ord key ⇒[(node, key, [key ])]→(Graph,Vertex→ (node, key, [key ]),
key → Maybe Vertex)
graphFromEdges′ -- nevrací mapu klíčůtransposeG :: Graph→ GraphtopSort :: Graph→ [Vertex ] -- topologické uspořádánídfs :: Graph→ [Vertex ]→ Forest Vertex -- zakořeněné kostrydff :: Graph→ Forest Vertex -- tosamé pro všechny kořenyscc :: Graph→ Forest Vertex -- souvislé komponentybcc :: Graph→ Forest [Vertex ] -- 2-souvislé komponenty
152
![Page 201: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/201.jpg)
Množiny a mapy
Standardní stromovité kontejnery: Map, IntMap, Set, IntSet
• Int-varianty jsou optimalizovanější• Jsou dostupné i Lazy varianty (většinou je vhodnější použít Strict)• Běžná metoda importu s kvalifikátorem zamezuje kolizi jmen:
import qualified Data.Map.Strict as M
• V balíku unordered-containers je navícHashSet aHashMapNB.: Hashování v kontejnerech je téměř vždy granát do vlastních bot; v případěfunkcionálního programování to platí exponenciálně víc. Pokud jste zvládli DS 2, PDS aVývoj vysoce výkonného SW a ještě pořád si myslíte, že to je dobrý nápad, můžete jepoužít.
153
![Page 202: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/202.jpg)
Data.Set, Data.Map
M.fromList :: Ord k ⇒ [(k, a)]→ M.Map k aS.fromList :: Ord a⇒ [a]→ S.Set aM.assocs :: M.Map k a→ [(k, a)]
M.elems :: M.Map k a→ [a]
S.elems :: S.Set a→ [a]
S.insert, S.delete :: Ord a⇒ a→ S.Set a→ S.Set aM.insert :: Ord k ⇒ k → a→ M.Map k a→ M.Map k aM.delete :: Ord k ⇒ k → M.Map k a→ M.Map k aM.adjust :: Ord k ⇒ (a→ a)→ k → M.Map k a→ M.Map k a(M.!) :: Ord k ⇒ M.Map k a→ k → a(M.!?) :: Ord k ⇒ M.Map k a→ k → Maybe aS.union, S.difference, S.intersection ::
Ord a⇒ S.Set a→ S.Set a→ S.Set a
154
![Page 203: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/203.jpg)
Funkcionální datové struktury
V jazycích bez mutovatelných hodnot tradiční datové struktury nefungujíúplně dobře!
Typický příklad: zápis jednoho prvku do vektoru musí zkopírovat celý blokdat (co kdyby původní vektor ještě nekdo potřeboval).
Některé struktury fungují pro některá použití částečně dobře:
• Zápis do hlavy/kořene v seznamu/stromě:O(1)• Obecně: zápis v hloubce h přepíšeO(h) dat.
155
![Page 204: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/204.jpg)
Funkcionální datové struktury
Funkcionální datové struktury minimalizují h.
• velké bloky dat snižují h ale zvyšují konstantní overhead• h je zdola omezené velikostí bloků a počtem uložených prvků
nh = O(Bh)
Běžné optimalizované struktury využívají např.:
• specializované části struktur• optimistické předpoklady o používání struktury
156
![Page 205: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/205.jpg)
Funkcionální fronta
Chceme potenciálně nekonečnou FIFO frontu sO(1) enqueue a dequeue.
Problémy:
• obousměrný seznam v immutable datech nejde vyrobit.• změna jednosměrného seznamu na konci stojíO(n) alokací
157
![Page 206: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/206.jpg)
Funkcionální fronta
Řešení: oddělíme polovinu fronty na čtení a polovinu fronty na zápis.
data FQueue a = FQueue {fqReadEnd :: [a], fqWriteEnd :: [a]}
fqEnqueue a q = q {fqWriteEnd = a : fqWriteEnd q}fqRefill (FQueue [ ] x) = FQueue (reverse x) [ ]
fqRefill q = qfqDequeue q = case fqRefill q ofr@(FQueue [ ] ) = NothingFQueue (r : rs) w = Just (r, FQueue rs w)
158
![Page 207: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/207.jpg)
Funkcionální fronta
Enqueue je viditelněO(1).
Dequeue je amortizovaněO(1). Pro každý průchozí prvek proběhnouoperace:
• připojení na začátek seznamu• reverse (konstantní cena za prvek)• odpojení ze začátku seznamu
159
![Page 208: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/208.jpg)
Zipper Tree
Zipper je generická konstrukce jak z normální datové struktury udělatvhodnou pro funkcionální programování. Princip si ukážeme na stromech.
• Normální stromy jsou reprezentované odkazem na kořen, hloubkavšech operací se měří seshora.
• Zipper tree jsou reprezentované odkazem na libovolný prvek, zekterého jdou ukazatele jak nahoru (až do kořene) tak dolů (až do listů).
160
![Page 209: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/209.jpg)
�
161
![Page 210: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/210.jpg)
�
161
![Page 211: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/211.jpg)
�
161
![Page 212: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/212.jpg)
�
Páteř je nutné specializovat.
161
![Page 213: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/213.jpg)
data BTree a = BNode (BTree a) a (BTree a) | Nildata ZSpine a = RootR a (BTree a)
| RootL (BTree a) a| SpineR (ZSpine a) a (BTree a)
| SpineL (BTree a) a (ZSpine a)
data ZBTree a = Root (BTree a) | NonRoot (BTree a) (ZSpine a)
zUp, zLeft, zRight :: ZBTree a→ ZBTree a
Implementace jde odvodit z původní struktury mechanicky pomocí derivacena termech. Koncept je aplikovatelný na jakoukoliv strukturu.
�Gerard Huet, “Functional Pearl: The Zipper.” Journal of FunctionalProgramming 7 (5), pp. 549–554 (1997).
162
![Page 214: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/214.jpg)
Standardní implementace operace find by vystoupala ke kořeni a použilahledání z BVS.
Úsporná implementace se při stoupání může zastavit dříve:
• hledaný prvek má klíč x• aktuální uzel je
• u = NonRoot (BNode lst a ) (SpineL b ) nebo• u = NonRoot (BNode lst a ) (RootL b)
• platí b < x < a• uzel s x existuje ⇐⇒ uzel je v podstromu lst
(platí i symetricky obráceně, s mírnou úpravou i pro intervaly)
163
![Page 215: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/215.jpg)
b
a
b < x < a
�
164
![Page 216: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/216.jpg)
Finger tree
�Ralf Hinze and Ross Paterson, “Finger trees: a simple general-purposedata structure.” Journal of Functional Programming 16:2 (2006), pp. 197–217.
Konstrukce: Zipper z ‘obou stran’ — strom je rozdělený podle podstromů odkraje, umožňuje rychlý přístup ke krajním prvkům a rychléspojování/rozpojování.
165
![Page 217: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/217.jpg)
Sekvence
Požadavky: přístup k oběma koncům, log-n nalezení k-tého prvku.
Implementace: 2-3 finger tree označkovaný velikostí podstromů.
Tradeoff: Sekvence nemůžou být nekonečné (narozdíl od seznamů).
166
![Page 218: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/218.jpg)
Rozdílový seznam
Známe z Prologu:
appendDiff(A-B,B-C,A-C).
?- L1=[1,2|End1]-End1, L2=[3,4|End2]-End2,appendDiff(L1,L2,Res-X).
Res = [1,2,3,4|X],End1 = [3,4|X],End2 = X.
Trik: Prologovou proměnnou jde zneužít jako skrytý pointer a přiřadit do ní vO(1) bez ohledu na to, jak je ve struktuře hluboko; stačí si ji poznamenat vmalé hloubce.
167
![Page 219: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/219.jpg)
Rozdílový seznam
Jaký mechanismus v Haskellu dovoluje přepsat nějakou skrytou hodnotu?
Líné vyhodnocování přepisuje thunky!
newtype DiffList a = DiffList {getDiff :: [a]→ [a]}
mkDiff = DiffList · (++)
unDiff = ($[ ]) · getDiffheadDiff = head · unDifftailDiff = DiffList · (tail·) · getDiffpushlDiff x = DiffList · (x:) · getDiffpushrDiff x (DiffList a) = DiffList (a · (x:))
appendDiff (DiffList a) (DiffList b) = DiffList (a · b)
...tvrdá skutečnost: a ++ b jeO(1), hlavní problém je čtení (tj. forcování)konce seznamu.
168
![Page 220: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/220.jpg)
Rozdílový seznam
Jaký mechanismus v Haskellu dovoluje přepsat nějakou skrytou hodnotu?Líné vyhodnocování přepisuje thunky!
newtype DiffList a = DiffList {getDiff :: [a]→ [a]}
mkDiff = DiffList · (++)
unDiff = ($[ ]) · getDiffheadDiff = head · unDifftailDiff = DiffList · (tail·) · getDiffpushlDiff x = DiffList · (x:) · getDiffpushrDiff x (DiffList a) = DiffList (a · (x:))
appendDiff (DiffList a) (DiffList b) = DiffList (a · b)
...tvrdá skutečnost: a ++ b jeO(1), hlavní problém je čtení (tj. forcování)konce seznamu.
168
![Page 221: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/221.jpg)
Rozdílový seznam
Jaký mechanismus v Haskellu dovoluje přepsat nějakou skrytou hodnotu?Líné vyhodnocování přepisuje thunky!
newtype DiffList a = DiffList {getDiff :: [a]→ [a]}
mkDiff = DiffList · (++)
unDiff = ($[ ]) · getDiffheadDiff = head · unDifftailDiff = DiffList · (tail·) · getDiffpushlDiff x = DiffList · (x:) · getDiffpushrDiff x (DiffList a) = DiffList (a · (x:))
appendDiff (DiffList a) (DiffList b) = DiffList (a · b)
...tvrdá skutečnost: a ++ b jeO(1), hlavní problém je čtení (tj. forcování)konce seznamu.
168
![Page 222: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/222.jpg)
Kompilujeme Haskell
![Page 223: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/223.jpg)
Průběh kompilace
1. Parsování2. Typecheck3. Desugaring (převod do jazyka Core)4. Optimalizace (“simplifier”)5. Převod do STG, optimalizace6. Převod do Cmm nebo LLVM, optimalizace7. sestavení8. linkování s RTS
169
![Page 224: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/224.jpg)
Simon Peyton Jones & Simon Marlow
169
![Page 225: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/225.jpg)
Jak typecheckovat funkcionální kód?
Rozdíl oproti C-like: postupování ‘po směru výpočtu’ nám toho moc neřekne.
• literály můžou mít libovolné typy, defaultovat a “kdyžtak pozdějikovertovat” nelze
• občas je potřeba odhadnout typ parametru funkce (auto-parametry vC++)
• v rekurzivních případech dopředné odvozování selže
Popíšeme si Hindley-Milnerův systém a jeho rozšíření o typové třídy.
170
![Page 226: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/226.jpg)
Lambda kalkulus
(c) Alonzo Church 1930
V ::=a|b|c| · · · |x∞Λ ::=V|ΛΛ|(λV.Λ)
Kupodivu:
• Systém je T-úplný• Díky jednoduchosti je to skvělý model pro “lidské” programovací
jazyky.
171
![Page 227: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/227.jpg)
Lambda kalkulus neumí hodnoty?
#haskell20:30 < Ariakenom> lambda calculus has both
functions and values,because functionsare values
171
![Page 228: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/228.jpg)
Alonzo Church
171
![Page 229: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/229.jpg)
λ-kuchařka
I = (λx.x), K = (λxy.x), K′ = (λxy.y),T = K, F = K′, if = (λbtf.btf) = I
0 = (λfx.x) = F, 1 = (λfx.fx) = I, 2 = (λfx.f(fx)), n = (λfx.fnx),add = (λabfx.af(bfx)), mul = (λabf.a(bf)), exp = (λab.ba)
Z? = (λn.n(KF)T), incr = add 1 = (λbfx.f(bfx)) = (λbfx.bf(fx))
pair = (λlrx.xlr), left = (λx.xT), right = (λx.xF)
decr = (λn.right(n incr2 (pair 0 0))),incr2 = (λp.pair (incr (left p)) (if (Z? (left p)) 0 (incr (right p))))
Rekurze bez možnosti použít vlastní definici:
facF = (λfn.if(Z? n) 1 (mul n (f(decr n))))
fac = Y facF, Y = (λf.(λx.f(xx))(λx.f(xx))),∞ = (λfx.Yfx) = Y172
![Page 230: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/230.jpg)
Věta o pevném bodě pro λ-kalkulus
(∀F)(∃X) X = F(X)
Dk.:
• Pomůcka: Y = (λf.(λx.f(xx))(λx.f(xx)))• X = YF, YF = F(YF). �
Pozorování: YF = F(YF) = F(F(YF)) = F∞(YF).
172
![Page 231: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/231.jpg)
Věta o pevném bodě pro λ-kalkulus
(∀F)(∃X) X = F(X)
Dk.:
• Pomůcka: Y = (λf.(λx.f(xx))(λx.f(xx)))
• X = YF, YF = F(YF). �
Pozorování: YF = F(YF) = F(F(YF)) = F∞(YF).
172
![Page 232: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/232.jpg)
Věta o pevném bodě pro λ-kalkulus
(∀F)(∃X) X = F(X)
Dk.:
• Pomůcka: Y = (λf.(λx.f(xx))(λx.f(xx)))• X = YF, YF = F(YF). �
Pozorování: YF = F(YF) = F(F(YF)) = F∞(YF).
172
![Page 233: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/233.jpg)
Věta o pevném bodě pro λ-kalkulus
(∀F)(∃X) X = F(X)
Dk.:
• Pomůcka: Y = (λf.(λx.f(xx))(λx.f(xx)))• X = YF, YF = F(YF). �
Pozorování: YF = F(YF) = F(F(YF)) = F∞(YF).
172
![Page 234: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/234.jpg)
Fixed point combinator
Y se tradičně jmenuje ‘fixed point combinator’ kvůli podobnosti sanalytickými větami o pevném bodě:
• Analýza: najdu x tak, že po spočítání (zachovávajícím ekvivalenci) zf(x) vyjde x, tudíž x = f(x).
• λ: najdu X tak, že po spočítání (zachovávajícím ekvivalenci) vyjdeF(X), tudíž X = F(X).
Teorie vyčíslitelnosti fixpointu říká ‘while cyklus’
• F∞(X) může cyklit donekonečna• podmínka v F může cyklus kdykoliv zastavit
D. Ú.: Na faktoriál přece není potřeba ani while-cyklus, ani dekrementace!Vyrobte fac bez decr a Y!
173
![Page 235: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/235.jpg)
Fixpoint v Haskellu
let fix f = f (fix f)
Cvičení (k vysvětlení výsledku):
• fix (λf i→ i : f (i + 1)) 1
• fix (1:)
• fix show
174
![Page 236: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/236.jpg)
Jak se nezacyklit
Pokud jde λ-term vůbec dostat do normální formy, určitě se do ní jde dostatpomocí vyhodnocování nejlevějšího redexu.
• (λx.xx) (λx.xx)
• K′ ((λx.xx) (λx.xx))(λx.x)
Tomu se říká lazy vyhodnocování.
175
![Page 237: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/237.jpg)
Bonus: Kombinátorový kalkulus
Uzavřeným termům se říká kombinátory. (F, K, S, I, ...)
Věta (SKI kalkulus): Každý λ-term lze vyjádřit jako výraz složený pouze zaplikací kombinátorů
S = λxyz.xz(yz)K = λxy.x
Např.:
I = SKKK′ = SKF = S(K(SI))K –flip
Y = S(K(SII))(S(S(KS)K)(K(SII)))
...176
![Page 238: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/238.jpg)
Bonus: Point-free
Trochu podobně se každý Haskellový term (bez speciální syntaxe) dá zbavitabstrakcí, výsledkem je tzv. point-free forma.
Konverze jednoduchých výrazů podle výskytu abstrahované proměnné:
λx→ x idλx→ a const aλx→ a x aλx→ a (b x) a · bλx→ (a x) b flip a bλx→ (a x) (b x) a 〈∗〉 bλx→ λy → a rekurzivně
Složitější termy obsahující x ‘někde hluboko’ je možné η-expandovat naněkterý z jednodušších případů a vyřešit rekurzivně.
177
![Page 239: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/239.jpg)
STLC
Jde nějak staticky zjistit, co daný λ-term dělá?
Nápad: zkusíme odvodit typ a uvidíme.
Jazyk typů:
VT ::=α|β|γ| · · · |τ∞T ::=VT|T → T
Tradiční zápis: Γ ` M : τ
Např.: ` I : τ → τ ` K : α→ β → α ` n : (σ → σ)→ σ → σ
` if : (α→ α→ α)→ α→ α→ α {x : α→ β, y : α} ` xy : β
178
![Page 240: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/240.jpg)
Mechanické odvození typů v STLC
x : τ ∈ ΓΓ ` x : τ
(Var)
Γ ` M : π → ρ Γ ` N : π
Γ ` MN : ρ(App)
Γ ∪ {v : π} ` M : ρ
Γ ` (λv.M) : (π → ρ)(Abs)
Pravidla se občas nazývají postupně Axiom,→-eliminace a→-zavedení.
179
![Page 241: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/241.jpg)
STLC
Slabá normalizace:
(∀M ∈ Λ) M : τ =⇒ Mmá N.F.
Nevýhoda: většina užitečného programování typ v STLC nemá, ale “shodouokolností” má normální formu. (typicky: Y)
Existují typové systémy se silnou normalizací (tj. kde právě všechnyzastavující programy mají typ), problém odvození typu v nich ale nenírozhodnutelný. Např. λ→∩Související: rozdíl mezi PRF, ORF a ČRF, viz. vyčíslitelnost.
180
![Page 242: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/242.jpg)
STLC
Slabá normalizace:
(∀M ∈ Λ) M : τ =⇒ Mmá N.F.
Nevýhoda: většina užitečného programování typ v STLC nemá, ale “shodouokolností” má normální formu. (typicky: Y)
Existují typové systémy se silnou normalizací (tj. kde právě všechnyzastavující programy mají typ), problém odvození typu v nich ale nenírozhodnutelný. Např. λ→∩Související: rozdíl mezi PRF, ORF a ČRF, viz. vyčíslitelnost.
180
![Page 243: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/243.jpg)
SystemF
Girard (1972) a nezávisle Reynolds (1974) z různých důvodů zavedlipolymorfní typování.
T ::= VT|T → T|∀VT.T
Extra pravidla:Γ ` M : σ α 6∈ Γ
Γ ` M : (∀α.σ)(Generalizace)
Γ ` M : (∀α.σ)
Γ ` M : σ[α := τ ](Specializace)
181
![Page 244: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/244.jpg)
Jean-Yves Girard & John C. Reynolds
181
![Page 245: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/245.jpg)
SystemF
Výhody:
• I : ∀α.α→ α, jde použít víckrát• (λx.xx) : (∀β.(∀α.α)→ β)
Nevýhody:
• (λx.xx) : (∀β.(∀α.α)→ (β → β))
• (λx.xx) : (∀α.α)→ (∀α.α)
• nerozhodnutelná inference. . .
Použití generalizace je příliš nedeterministické. Zkusme to rozumně.
182
![Page 246: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/246.jpg)
Hindley-Milnerův systém
Zavedeme novou jazykovou konstrukci let v = d in e, jejímž výsledkembude polymorfní v použitelné v e.
Generalizaci v typech můžeme omezit na “vrchní úroveň”.
Λ ::=V|ΛΛ|(λV.Λ)|let V = Λ in Λ
M ::=VT|M →M (monotypy)P ::=M|∀VT.P (polymorfní typy)
183
![Page 247: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/247.jpg)
H-M
Odpovídající úprava STLC:x : τ ∈ Γ τ ∈M
Γ ` x : τ(Var)
x : τ ∈ Γ τ ∈ PΓ ` x : INSTANTIATE(τ)
(Var-Inst)
Γ ` a : π → ρ Γ ` b : π
Γ ` a b : ρ(App)
Γ ∪ {v : π} ` e : ρ
Γ ` (λv.e) : (π → ρ)(Abs)
Γ ` d : τ Γ ∪ {v : QUANTIFY(τ)} ` e : σ
Γ ` (let v = d in e) : σ(Let-Gen) 184
![Page 248: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/248.jpg)
Běžná implementace H-M
• Proměnné zachycené v let přiřadíme nejobecnější možný typ.• Pokud někde použijeme polymorfní proměnnou, typ instancujeme na
monomorfní typ doplněním čerstvých typových proměnných zapolymorfní.
Př.: let I = (λx.x) in I I
• (λx.x) : α→ α
• I : ∀α.α→ α
• Druhé I: β → β
• První I: γ → γ, posléze (β → β)→ (β → β)
• Celý výraz: β → β
185
![Page 249: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/249.jpg)
Bez instancování není polymorfismu!
id id :: a→ a
ale:
(λx→ x x) id
Occurs check: cannot construct the infinite type:t ∼ t→ t
185
![Page 250: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/250.jpg)
Typové třídy
Rozšíření H-M pro podporu typových tříd:
• kvalifikované polymorfní typykvalifikace je efektivně množina tvrzení o typových proměnných (vetvaru predikátů)
• kontroly typových tříd při specializaci• složitější hledání nejobecnějšího typu
• v rekurzivním případě to je nerozhodnutelný problém• některé odvozené predikáty patří kontextu
(typicky ve vnořených definicích)• některé typy dovolují nejednoznačné chováníf = show · read
�Mark P. Jones, “Typing Haskell In Haskell.”http://web.cecs.pdx.edu/~mpj/thih/
186
![Page 251: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/251.jpg)
Rekurzivní polymorfismus
Typ vzájemně polymorfních rekurzivních definic není možné automatickyodvodit!
data Seq a = Nil | Cons a (Seq (a, a))
seqmap f Nil = Nilseqmap f (Cons x xs) =
Cons (f x) (seqmap (λ(a, b)→ (f a, f b)) xs)
Error: cannot construct the infinite type...
Oprava: typ připíšeme ručně.
seqmap :: (a→ b)→ Seq a→ Seq b
187
![Page 252: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/252.jpg)
Defaulting
f = show · readf :: String→ String
...ale co se vlastně stane uvnitř?
Podobně:
main = print 5
Vypíše se Int, Integer, Float, nebo něco jiného?
Defaulting: Kompilátor v takových případech vyzkouší přednastavenédefaultní typy.
Běžně např: default (Integer,Double)
Defaulting jde pro modul vypnout: default ()
188
![Page 253: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/253.jpg)
Defaulting zevnitř
f x = show (read x)
read :: Read a⇒ String→ ax :: String(read x) :: Read a⇒ ashow :: Show a⇒ a→ Stringshow (read x) :: (Read a, Show a)⇒ Stringf :: (Read a, Show a)⇒ String→ String
Nepoužitá kvalifikovaná proměnná označuje nějakou nejednoznačnost(ambiguity).
Nejednoznačnosti se odstraní vyhledáním prvního typu ze seznamudefault, který vyhovyje všem predikátům (případně chybou).
189
![Page 254: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/254.jpg)
Typový systém Haskellu
Haskell navíc obsahuje poměrně velké množství rozšíření:
• víceparametrové typové třídy• DataKinds, “dependent” types• explicitní typovou rovnost• type families• lineární typy• . . .
190
![Page 255: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/255.jpg)
Core
Kód který prošel typecheckem se transformuje na Core.
data Expr b =
Var Id| Lit Literal| App (Expr b) (Arg b)
| Lam b (Expr b)
| Let (Bind b) (Expr b)
| Case (Expr b) b Type [Alt b]
| Cast (Expr b) Coercion| Tick (Tickish Id) (Expr b)
| Type Type| Coercion Coercionderiving Data
(CoreSyn.hs:255-266) 191
![Page 256: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/256.jpg)
Core
Výhody:
• na jednoduchý kód se jednoduše píšou transformace• DCE• Inlining• Specializace
• jde typecheckovat (tj. ověřovat správnost transformací)
Zajímavosti:
• z kvantifikace typů se stávají parametry funkcí• typové třídy se do Core ani nedostanou (jsou předělané na slovníkové
funkce)
192
![Page 257: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/257.jpg)
STG
Spineless Tagless Graph machine je VM pro vykonávání Haskellu.
VM obsahuje:
• registry• stack
• Haskell nemá viditelný stack!• používaný na continuations
• heap• data• thunks• functions• continuations
Hodnoty na heapu jsou propojené pointery.
193
![Page 258: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/258.jpg)
STG a laziness
Data mají mnoho podob:
• unboxed — P. O. D.• boxed, unlifted — mají ‘obal’ který místo nich může obsahovat thunk,
ale nemůžou být⊥.• boxed, lifted — mají ‘obal’ a navíc můžou být⊥ (vyrobit výjimku).
Život na STG:
• funkce je pointer na kód s aritou a uzávěrem• přidáním dostatku argumentů se funkce změní na thunk• forcováním se thunk (občas) změní na data
Laziness je důsledkem oddělení aplikace funkcí a vlastního výpočtu.
194
![Page 259: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/259.jpg)
Trocha šetření
Aby se funkce zbytečně nepočítaly víckrát než je potřeba, Haskell pro každýlet-binding v kódu vygeneruje pouze jeden thunk při každém vstupu doscope.
Když nějaká část programu thunk poprvé spočítá, nahradí ho výsledkem, tenmůžou dál používat i ostatní části programu.
Výsledek:
• Let-binding bez parametrů se vždycky vypočítá jen jednou• Funguje fibs = 0 : 1 : zipWith (+) fibs (tail fibs)• monomorphism restriction
195
![Page 260: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/260.jpg)
Trocha šetření
Aby se funkce zbytečně nepočítaly víckrát než je potřeba, Haskell pro každýlet-binding v kódu vygeneruje pouze jeden thunk při každém vstupu doscope.
Když nějaká část programu thunk poprvé spočítá, nahradí ho výsledkem, tenmůžou dál používat i ostatní části programu.
Výsledek:
• Let-binding bez parametrů se vždycky vypočítá jen jednou• Funguje fibs = 0 : 1 : zipWith (+) fibs (tail fibs)• monomorphism restriction
195
![Page 261: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/261.jpg)
Trocha šetření
Aby se funkce zbytečně nepočítaly víckrát než je potřeba, Haskell pro každýlet-binding v kódu vygeneruje pouze jeden thunk při každém vstupu doscope.
Když nějaká část programu thunk poprvé spočítá, nahradí ho výsledkem, tenmůžou dál používat i ostatní části programu.
Výsledek:
• Let-binding bez parametrů se vždycky vypočítá jen jednou• Funguje fibs = 0 : 1 : zipWith (+) fibs (tail fibs)• monomorphism restriction
195
![Page 262: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/262.jpg)
Trocha šetření
Aby se funkce zbytečně nepočítaly víckrát než je potřeba, Haskell pro každýlet-binding v kódu vygeneruje pouze jeden thunk při každém vstupu doscope.
Když nějaká část programu thunk poprvé spočítá, nahradí ho výsledkem, tenmůžou dál používat i ostatní části programu.
Výsledek:
• Let-binding bez parametrů se vždycky vypočítá jen jednou• Funguje fibs = 0 : 1 : zipWith (+) fibs (tail fibs)• monomorphism restriction
195
![Page 263: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/263.jpg)
Odstranění implicitního scope: Lifting
Asembler, STG ani Cmm nemají scope. Lifting je jednoduchá transformace,která scope doplní:
solutions a b c = map (/(2 ∗ a)) [−b + sD,−b− sD]
where sD = sqrt (b ∗ b− 4 ∗ a ∗ c)
Doplnění argumentů:
solutions a b c = map (/(2 ∗ a)) [−b + sD a b c,−b− sD a b c ]
where sD a b c = sqrt (b ∗ b− 4 ∗ a ∗ c)
Lift:
sD a b c = sqrt (b ∗ b− 4 ∗ a ∗ c)solutions a b c = map (/(2 ∗ a)) [−b + sD a b c,−b− sD a b c ]
196
![Page 264: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/264.jpg)
Odstranění přímé rekurze a stacku
Konverze na Continuation-Passing-Style:
sD a b c cont = cont (sqrt (b ∗ b− 4 ∗ a ∗ c))
solutions a b c cont =
sD a b c $ λd1→map (/(2 ∗ a)) [−b + d1,−b− d1] cont
(sqrt a ostatní číselné operace považujeme za primitivní)
Continuation je víceméně jen pointer na kód.
197
![Page 265: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/265.jpg)
Low-level
• STG se (už poměrně jednoduše) převede na Cmm• Cmm je C s garbage collectorem, ale bez složitých typů a pořádných
pointerů
• Cmm jde skompilovat podobně jako C na modul .o• Výsledek se slinkuje s RTS, který doplní:
• main• Cmm rutiny pro GC (alokaci apod.)• Cmm rutiny pro IO• implementaci spodních vrstev GHC.Prim
198
![Page 266: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/266.jpg)
Low-level: moduly
Modularizace funguje obdobně jako u C/C++:
• .hs odpovídá zdrojovému kódu .c a .cpp• .hi odpovídá vygenerovaným hlavičkovým souborům• .o odpovídá Cčkovému .o, jde předělat na .so nebo .a (případně.dll a .lib) a standardně linkovat
Typický problém: Změny v .hi (i špatné) se mohou propagovat do jiných.hi. (Tradiční řešení: cabal nuke)
199
![Page 267: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/267.jpg)
Curry-Howardova korespondence
![Page 268: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/268.jpg)
Co vlastně znamená typ nějakého výrazu?
• Tradiční jazyky: Formát dat (zhruba)• Funkcionální programování: jaký formát má→ ?
200
![Page 269: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/269.jpg)
Motivace
Motivační úkol: Napište funkci f , která má typ f :: a→ b.
1. Dostanu a, zahodím ho, OK.2. Vyrobím nějaké b?
(λx→ 1) :: a→ Integer 6≡ a→ b
f :: a→ b znamená f :: ∀a.∀b.a→ b. Program tímto slibuje, že budeumět vyrobit jakékoliv b.
Haskell-style řešení:
(λ → ⊥) :: p→ a
201
![Page 270: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/270.jpg)
Motivace
Motivační úkol: Napište funkci f , která má typ f :: a→ b.
1. Dostanu a, zahodím ho, OK.
2. Vyrobím nějaké b?(λx→ 1) :: a→ Integer 6≡ a→ b
f :: a→ b znamená f :: ∀a.∀b.a→ b. Program tímto slibuje, že budeumět vyrobit jakékoliv b.
Haskell-style řešení:
(λ → ⊥) :: p→ a
201
![Page 271: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/271.jpg)
Motivace
Motivační úkol: Napište funkci f , která má typ f :: a→ b.
1. Dostanu a, zahodím ho, OK.2. Vyrobím nějaké b?
(λx→ 1) :: a→ Integer 6≡ a→ b
f :: a→ b znamená f :: ∀a.∀b.a→ b. Program tímto slibuje, že budeumět vyrobit jakékoliv b.
Haskell-style řešení:
(λ → ⊥) :: p→ a
201
![Page 272: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/272.jpg)
Motivace
Motivační úkol: Napište funkci f , která má typ f :: a→ b.
1. Dostanu a, zahodím ho, OK.2. Vyrobím nějaké b?
(λx→ 1) :: a→ Integer 6≡ a→ b
f :: a→ b znamená f :: ∀a.∀b.a→ b. Program tímto slibuje, že budeumět vyrobit jakékoliv b.
Haskell-style řešení:
(λ → ⊥) :: p→ a
201
![Page 273: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/273.jpg)
Motivace
Motivační úkol: Napište funkci f , která má typ f :: a→ b.
1. Dostanu a, zahodím ho, OK.2. Vyrobím nějaké b?
(λx→ 1) :: a→ Integer 6≡ a→ b
f :: a→ b znamená f :: ∀a.∀b.a→ b. Program tímto slibuje, že budeumět vyrobit jakékoliv b.
Haskell-style řešení:
(λ → ⊥) :: p→ a
201
![Page 274: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/274.jpg)
Sémantika→
Použitím a→ b tvrdíme, že z věci s typem a umíme vyrobit věc s typem b.
202
![Page 275: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/275.jpg)
Sémantika→
Použitím a→ b tvrdíme, že z věci s typem a umíme vyrobit věc s typem b.
202
![Page 276: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/276.jpg)
Typy jako tvrzení
• → si můžeme představit jako logickou implikaci• místo konjunkce a ∧ b použijeme typ n-tice (a, b)
• místo disjunkce a ∨ b použijeme Either a b
Např.: viditelně neplatí, že
a→ (a, b)
ale pokud nám někdo navíc dá způsob jak vyrábět b z a, může platit:
(a→ b)→ (a→ (a, b))
203
![Page 277: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/277.jpg)
Programy jako důkazy
Curry-Howard: Program s typem t existuje právě, když jetvrzení odpovídající t dokazatelné v přirozené logice.
203
![Page 278: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/278.jpg)
Programy jako důkazy
(λx→ (x,⊥)) :: a→ (a, b)
(program obsahuje chybu, tvrzení neplatí)
(λf x→ (x, f x)) :: (a→ b)→ (a→ (a, b))
(tvrzení platí)
204
![Page 279: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/279.jpg)
Korespondence
Axiom logiky λ-kalkulusZeslabení(φ =⇒ (ψ =⇒ φ))
` K : α→ β → α
Substituce S = (λxyz.xz(yz))
` S : (α→ β → γ)→ (α→ β)→ α→ γ
Modus ponens {A : α→ β,B : α} ` AB : β
` I : (α→ β)→ α→ β
Hledání důkazu Inhabitace typu
Extra korespondující tvrzení:
• Kombinováním axiomů lze sestrojit jakékoliv tvrzení• Kombinováním SKI lze sestrojit jakýkoliv program
(včetně Turingova stroje)205
![Page 280: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/280.jpg)
Korespondence
Axiom logiky λ-kalkulusZeslabení(φ =⇒ (ψ =⇒ φ))
` K : α→ β → α
Substituce S = (λxyz.xz(yz))
` S : (α→ β → γ)→ (α→ β)→ α→ γ
Modus ponens {A : α→ β,B : α} ` AB : β
` I : (α→ β)→ α→ β
Hledání důkazu Inhabitace typu
Extra korespondující tvrzení:
• Kombinováním axiomů lze sestrojit jakékoliv tvrzení• Kombinováním SKI lze sestrojit jakýkoliv program
(včetně Turingova stroje)205
![Page 281: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/281.jpg)
Příklad
Chci dokázat: a ∧ (b ∨ c) =⇒ (a ∧ b) ∨ (a ∧ c)
p :: (a, Either b c)→ Either (a, c) (a, b)
p (a, e) = case e of Left b→ Right (a, b)
Right c→ Left (a, c)
Výhoda: prohledávání termů je algoritmicky poměrně jednoduché.
Hlavní implementace: Agda, Coq, HOL, Djinn
206
![Page 282: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/282.jpg)
Příklad
Chci dokázat: a ∧ (b ∨ c) =⇒ (a ∧ b) ∨ (a ∧ c)
p :: (a, Either b c)→ Either (a, c) (a, b)
p (a, e) = case e of Left b→ Right (a, b)
Right c→ Left (a, c)
Výhoda: prohledávání termů je algoritmicky poměrně jednoduché.
Hlavní implementace: Agda, Coq, HOL, Djinn
206
![Page 283: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/283.jpg)
Příklad
Chci dokázat: a ∧ (b ∨ c) =⇒ (a ∧ b) ∨ (a ∧ c)
p :: (a, Either b c)→ Either (a, c) (a, b)
p (a, e) = case e of Left b→ Right (a, b)
Right c→ Left (a, c)
Výhoda: prohledávání termů je algoritmicky poměrně jednoduché.
Hlavní implementace: Agda, Coq, HOL, Djinn
206
![Page 284: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/284.jpg)
Co s negací?
Logika λ-kalkulusTrue ()
False Void¬a a→ VoidSpornost teorie ⊥
Void nejde vyrobit, můžeme ho jen ‘přeposlat’ dál.
Pozor, v intuicionistické logice neplatí¬¬a = a!
S trochou přidané magie jde vyrobit:
throw :: a→ Voidcatch :: ((a→ Void)→ Void)→ a
207
![Page 285: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/285.jpg)
Co s negací?
Logika λ-kalkulusTrue ()
False Void¬a a→ VoidSpornost teorie ⊥
Void nejde vyrobit, můžeme ho jen ‘přeposlat’ dál.
Pozor, v intuicionistické logice neplatí¬¬a = a!
S trochou přidané magie jde vyrobit:
throw :: a→ Voidcatch :: ((a→ Void)→ Void)→ a
207
![Page 286: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/286.jpg)
Co si z toho odnést?
• Funkce je důkazem existence datové transformace• Kód funkce jde automaticky odvodit z typu
• přesnější typ =⇒ méně validních implementací=⇒ méně chyb
• implementaci podle dostatečně přesného typu může zařídit počítač(viz. Coq&Agda)
• obecnější typ může být restriktivnější
• Je vhodné se podobně chovat i ke specifikacím dat(data mají typ ⇐⇒ jsou validní)
208
![Page 287: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/287.jpg)
Co si z toho odnést?
• Funkce je důkazem existence datové transformace• Kód funkce jde automaticky odvodit z typu
• přesnější typ =⇒ méně validních implementací=⇒ méně chyb
• implementaci podle dostatečně přesného typu může zařídit počítač(viz. Coq&Agda)
• obecnější typ může být restriktivnější
• Je vhodné se podobně chovat i ke specifikacím dat(data mají typ ⇐⇒ jsou validní)
208
![Page 288: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/288.jpg)
Těsné typy
Jak produkovat typově odolný kód:
1. psát generičtější funkce2. používat specifičtější datové typy (přesnější, ‘těsné’, ‘tight’)
Generické funkce fungují na víc dat (šetří kód), jejich typ je ale ve skutečnostirestriktivnější!
Specifičtější data výrazně zjednodušují okolní program (je v něm míň ifů).
209
![Page 289: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/289.jpg)
Těsné typy
Typické nepřesné datové konstrukce:
• null-member místo více variant celého objektu• seznamy místo n-tic nebo záznamů• XML
210
![Page 290: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/290.jpg)
Těsné typy
Opačný problém: Kompilátor CakeML má (přesné) typy pro všech cca. 20různých reprezentací mezikódu v pipeline.
• Výhoda: verifikovat ho je zábava na 10 minut• Nevýhoda: Není rozumné psát skoro stejnou funkci pro 20 různých
datových typů• Řešení:
feature-based typové třídy poskytující generický přístup kespecifickým vlastnostem.
• Např. HasVars, Formattable, ...• THIH:
• Type, Pred,Qual t, Scheme, Assump∈ Types• Type, [a], Pred,Qual t ∈ Instantiate
• -XOverloadedRecords
211
![Page 291: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/291.jpg)
Těsné typy
Opačný problém: Kompilátor CakeML má (přesné) typy pro všech cca. 20různých reprezentací mezikódu v pipeline.
• Výhoda: verifikovat ho je zábava na 10 minut• Nevýhoda: Není rozumné psát skoro stejnou funkci pro 20 různých
datových typů• Řešení: feature-based typové třídy poskytující generický přístup ke
specifickým vlastnostem.• Např. HasVars, Formattable, ...• THIH:
• Type, Pred,Qual t, Scheme, Assump∈ Types• Type, [a], Pred,Qual t ∈ Instantiate
• -XOverloadedRecords
211
![Page 292: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/292.jpg)
Optika, čočky a hranoly
![Page 293: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/293.jpg)
Motivace
OOP universe · galaxy (milky) · sun · earth ·matfyz ·rooms [S4] ·molecules [23] · atom [0] ; "N"
Haskell (head·atoms·(!!23)·molecules·(!!S4)·rooms·matfyz·earth · sun · (!!milky) · galaxies) universe ; "N"
OOP universe · galaxy (milky) · sun · earth ·matfyz ·rooms [S4] ·molecules [23] · atom [1] = "Au"
Haskell /
212
![Page 294: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/294.jpg)
Motivace
OOP universe · galaxy (milky) · sun · earth ·matfyz ·rooms [S4] ·molecules [23] · atom [0] ; "N"
Haskell (head·atoms·(!!23)·molecules·(!!S4)·rooms·matfyz·earth · sun · (!!milky) · galaxies) universe ; "N"
OOP universe · galaxy (milky) · sun · earth ·matfyz ·rooms [S4] ·molecules [23] · atom [1] = "Au"
Haskell /
212
![Page 295: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/295.jpg)
Problém
Vybírání podstruktur v OOP ve skutečnosti nevrací data, ale reference.Haskell jednoduché jazykové reference nemá. (IORef apod. se nepočítá)
Co s tím?
Software engineering! Reference nasimulujeme.
Co jde dělat s referencí?
• get• set• vyrobit z ní subreferenci
Jaká funkcionální hodnota může mít všechny tyto vlastnosti najednou?
213
![Page 296: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/296.jpg)
Problém
Vybírání podstruktur v OOP ve skutečnosti nevrací data, ale reference.Haskell jednoduché jazykové reference nemá. (IORef apod. se nepočítá)
Co s tím? Software engineering! Reference nasimulujeme.
Co jde dělat s referencí?
• get• set• vyrobit z ní subreferenci
Jaká funkcionální hodnota může mít všechny tyto vlastnosti najednou?
213
![Page 297: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/297.jpg)
Co jde dělat s referencí? (přesněji)
• vybrat hluboce zanořenou část nějakého velkého objektu• změnit část nějakého objektu• skombinovat ji s jinou (sub)referencí a dostat hlubší referenci
První pokus:
data Lens big small = Lens{view :: big→ small, over :: (small→ small)→ (big→ big)
}
214
![Page 298: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/298.jpg)
Co jde dělat s referencí? (přesněji)
• vybrat hluboce zanořenou část nějakého velkého objektu• změnit část nějakého objektu• skombinovat ji s jinou (sub)referencí a dostat hlubší referenci
První pokus:
data Lens big small = Lens{view :: big→ small, over :: (small→ small)→ (big→ big)
}
214
![Page 299: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/299.jpg)
Pokus 1
data Lens big small = Lens{view :: big→ small, over :: (small→ small)→ (big→ big)}
data Two a = Two a a deriving Showx = Lens (λ(Two a )→ a) (λf (Two a b)→ Two (f a) b)
y = Lens (λ(Two b)→ b) (λf (Two a b)→ Two a (f b))
t = Two 1 2
view x t ; 1over y (+1) t ; Two 1 3
set x v = over x (const v)
set x 5 t ; Two 5 2
215
![Page 300: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/300.jpg)
Pokus 1
(Lens v1 o1) ‘sub‘ (Lens v2 o2) =
Lens (v2 · v1) (λf → o1 (o2 f))
t = Two (Two 1 2) (Two 3 4)
: t x ‘sub‘ y ; Lens (Two (Two b)) bview (x ‘sub‘ y) t ; 2over (x ‘sub‘ y) (∗10) t ; Two (Two 1 20) (Two 3 4)
216
![Page 301: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/301.jpg)
Zlepšení
• Všichni jsou zvyklí na tečku! Chceme x · y · x• Co takhle něco lepšího než tradiční OOP?
• Jak správně udělat referenci na objekt, který nemusí být k dispozici?left :: Lens (Either a b) a ?
• Nejde udělat referenci na víc objektů, podobně ve vektorových jazycích?Clamp v Rku: x [x < 0] = 0; x [x > 1] = 1;
• Co když chceme změnit typ uvnitř velkého objektu?
Začneme tím složitějším.
217
![Page 302: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/302.jpg)
Zlepšení
• Všichni jsou zvyklí na tečku! Chceme x · y · x• Co takhle něco lepšího než tradiční OOP?
• Jak správně udělat referenci na objekt, který nemusí být k dispozici?left :: Lens (Either a b) a ?
• Nejde udělat referenci na víc objektů, podobně ve vektorových jazycích?Clamp v Rku: x [x < 0] = 0; x [x > 1] = 1;
• Co když chceme změnit typ uvnitř velkého objektu?
Začneme tím složitějším.
217
![Page 303: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/303.jpg)
Optika, pokus 2
Máme:
(·) :: (b→ c)→ (a→ b)→ (a→ c)
Chceme:
(·) :: Lens x y → Lens y z→ Lens x z
Lens tedy musí být funkce:
type Lens a b = →
Zároveň víme:
set′ :: ( → )→ (b→ b)→ (a→ a)
get′ :: ( → )→ (b→ b)→ (a→ b)
Z jakého ( → ) jde jednoduše udělat get i set?
218
![Page 304: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/304.jpg)
Optika, pokus 2
Pokračujeme:
(·) :: (b→ c)→ (a→ b)→ (a→ c)(·) :: Lens x y → Lens y z→ Lens x z
Pořadí parametrů musí odpovídat
Lens big small = Neco small→ Neco big
tj. čočka jako funkce konvertuje ‘Něco pracující s částí’ na ’Něco pracující scelkem’.
Takovou funkci potřebujeme použít v:
set′ :: (Neco small→ Neco big)→ (small→ small)→ (big→ big)
get′ :: (Neco small→ Neco big)→ (small→ small)→ (big→ small)
Neco big očividně musí být konvertovatelné na small i big!
219
![Page 305: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/305.jpg)
Optika, pokus 2
Pokračujeme:
(·) :: (b→ c)→ (a→ b)→ (a→ c)(·) :: Lens x y → Lens y z→ Lens x z
Pořadí parametrů musí odpovídat
Lens big small = Neco small→ Neco big
tj. čočka jako funkce konvertuje ‘Něco pracující s částí’ na ’Něco pracující scelkem’.
Takovou funkci potřebujeme použít v:
set′ :: (Neco small→ Neco big)→ (small→ small)→ (big→ big)
get′ :: (Neco small→ Neco big)→ (small→ small)→ (big→ small)
Neco big očividně musí být konvertovatelné na small i big!
219
![Page 306: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/306.jpg)
Optika, pokus 2
Pokračujeme:
(·) :: (b→ c)→ (a→ b)→ (a→ c)(·) :: Lens x y → Lens y z→ Lens x z
Pořadí parametrů musí odpovídat
Lens big small = Neco small→ Neco big
tj. čočka jako funkce konvertuje ‘Něco pracující s částí’ na ’Něco pracující scelkem’.
Takovou funkci potřebujeme použít v:
set′ :: (Neco small→ Neco big)→ (small→ small)→ (big→ big)
get′ :: (Neco small→ Neco big)→ (small→ small)→ (big→ small)
Neco big očividně musí být konvertovatelné na small i big!
219
![Page 307: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/307.jpg)
Optika, pokus 2
Za cenu drobného zkomplikování interface můžeme dovnitř vrazit nějakou(parametrizovatelnou) dekoraci:
type Neco a = a→ Dekorace aset′ :: ((small→ Set small)→ (big→ Set big))→
(small→ Set small)→ (big→ Set big)
get′ :: ((small→ Get small)→ (big→ Get big))→(small→ Get small)→ (big→ Get big)
Uživatel dodá funkce pracující s dekorací, tu si nakonec sám odstraní.
Potřebujeme, aby po odstranění dekorace platilo:
Set small ; smallSet big ; bigGet small ; smallGet big ; small
id S ; Sid B ; Bconst S S ; Sconst S B ; S
220
![Page 308: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/308.jpg)
Optika, pokus 2
Za cenu drobného zkomplikování interface můžeme dovnitř vrazit nějakou(parametrizovatelnou) dekoraci:
type Neco a = a→ Dekorace aset′ :: ((small→ Set small)→ (big→ Set big))→
(small→ Set small)→ (big→ Set big)
get′ :: ((small→ Get small)→ (big→ Get big))→(small→ Get small)→ (big→ Get big)
Uživatel dodá funkce pracující s dekorací, tu si nakonec sám odstraní.Potřebujeme, aby po odstranění dekorace platilo:
Set small ; smallSet big ; bigGet small ; smallGet big ; small
id S ; Sid B ; Bconst S S ; Sconst S B ; S
220
![Page 309: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/309.jpg)
Optika, pokus 2
Za cenu drobného zkomplikování interface můžeme dovnitř vrazit nějakou(parametrizovatelnou) dekoraci:
type Neco a = a→ Dekorace aset′ :: ((small→ Set small)→ (big→ Set big))→
(small→ Set small)→ (big→ Set big)
get′ :: ((small→ Get small)→ (big→ Get big))→(small→ Get small)→ (big→ Get big)
Uživatel dodá funkce pracující s dekorací, tu si nakonec sám odstraní.Potřebujeme, aby po odstranění dekorace platilo:
Set small ; smallSet big ; bigGet small ; smallGet big ; small
id S ; Sid B ; Bconst S S ; Sconst S B ; S 220
![Page 310: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/310.jpg)
220
![Page 311: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/311.jpg)
Optika, pokus 2
runIdentity :: Identity small → smallrunIdentity :: Identity big → biggetConst :: (Const small) small→ smallgetConst :: (Const small) big → small
Dostáváme:
set′ :: ((small→ Identity small)→ (big→ Identity big))→(small→ Identity small)→ (big→ Identity big)
set′ = idover lens f = runIdentity · lens (Identity · f)get′ :: ((small→ Const small small)→ (big→ Const small big))→
(small→ Const small small)→ (big→ Const small big)
get′ = idviewed lens f = getConst · lens (Const · f) 221
![Page 312: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/312.jpg)
Optika — implementace
Jak vypadá implementace čočky?
:: forall x · (small→ x small)→ big→ x big
• dostane funkci, která malou ‘součást’ něčím obalí• má vyrobit funkci, která umí tím samým obalit velký ‘celek’• moc typově validních implementací nemáme:
1. celek dostaneme (jako parametr typu big)2. z celku vyřízneme část typu small3. small si můžeme nechat obalit na x small4. z x small chceme udělat x big, ale umíme jen small→ big5. když je x funktor, můžeme to udělat pomocí fmap
Lens jde takto triviálně vyrobit z getteru a setteru.
222
![Page 313: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/313.jpg)
Optika — implementace
Jak vypadá implementace čočky?
:: forall x · (small→ x small)→ big→ x big
• dostane funkci, která malou ‘součást’ něčím obalí• má vyrobit funkci, která umí tím samým obalit velký ‘celek’• moc typově validních implementací nemáme:
1. celek dostaneme (jako parametr typu big)2. z celku vyřízneme část typu small3. small si můžeme nechat obalit na x small4. z x small chceme udělat x big, ale umíme jen small→ big5. když je x funktor, můžeme to udělat pomocí fmap
Lens jde takto triviálně vyrobit z getteru a setteru.
222
![Page 314: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/314.jpg)
Optika — implementace
Jak vypadá implementace čočky?
:: forall x · (small→ x small)→ big→ x big
• dostane funkci, která malou ‘součást’ něčím obalí• má vyrobit funkci, která umí tím samým obalit velký ‘celek’• moc typově validních implementací nemáme:
1. celek dostaneme (jako parametr typu big)2. z celku vyřízneme část typu small3. small si můžeme nechat obalit na x small4. z x small chceme udělat x big, ale umíme jen small→ big5. když je x funktor, můžeme to udělat pomocí fmap
Lens jde takto triviálně vyrobit z getteru a setteru.
222
![Page 315: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/315.jpg)
Optika — implementace
Jak vypadá implementace čočky?
:: forall x · (small→ x small)→ big→ x big
• dostane funkci, která malou ‘součást’ něčím obalí• má vyrobit funkci, která umí tím samým obalit velký ‘celek’• moc typově validních implementací nemáme:
1. celek dostaneme (jako parametr typu big)2. z celku vyřízneme část typu small3. small si můžeme nechat obalit na x small4. z x small chceme udělat x big, ale umíme jen small→ big5. když je x funktor, můžeme to udělat pomocí fmap
Lens jde takto triviálně vyrobit z getteru a setteru.
222
![Page 316: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/316.jpg)
Optika – výsledek
Celkový typ čočky (potřebuje -XRankNTypes):
type Lens a b = forall f · Functor f ⇒ (b→ f b)→ (a→ f a)
Jak vypadá funktorový lens?
x :: Lens (Two a) ax :: Functor f ⇒ (a→ f a)→ (Two a→ f (Two a))
x ff (Two a b) = fmap (λa′ → Two a′ b) $ ff ay ff (Two a b) = fmap (λb′ → Two a b′) $ ff b
Genericky z getteru a setteru:
lens :: (a→ b)→ (a→ b→ a)→ Lens a blens getter setter ff a = fmap (setter a) $ ff (getter a)
223
![Page 317: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/317.jpg)
Optika vs. tečka
Typový úspěch:
(·) :: Functor f⇒ ((b→ f b)→ (a→ f a))
→ ((c→ f c)→ (b→ f b))
→ ((c→ f c)→ (a→ f a))
(·) :: Lens a b→ Lens b c→ Lens a c
(a, b jsou v definici Lens prohozené!)
224
![Page 318: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/318.jpg)
Optika — implementace
Tradičně k dispozici:
set :: Lens a b→ b→ a→ aset l v = runIdentity · l (Identity · const v)
over :: Lens a b→ (b→ b)→ a→ aover l f = runIdentity · l (Identity · f)view :: Lens a b→ a→ bview l = getConst · l Const
225
![Page 319: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/319.jpg)
Optika — použití
set x :: b→ Two b→ Two bover (x · y) (+1) :: Num b⇒ Two (Two b)→ Two (Two b)
view (x · y · x) :: Two (Two (Two b))→ b
Příjemný bonus: Lensy se skládají v přirozenějším pořadí
set (x · y) 10 (Two (Two 1 2) (Two 3 4))
; Two (Two 1 10) (Two 3 4)
226
![Page 320: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/320.jpg)
Edward Kmett
“newtype PlanT k i o m a = PlanT {runPlanT ::forall r ·(a→ m r)→ (o→
m r → m r)→ (forall z · (z→ m r)→ k i z→ m r → m r)→ m r → m r}
is a monad I actually use.”226
![Page 321: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/321.jpg)
Víc optiky!
Problémy:
• allItems :: Lens [a]
• left :: Lens (Either a b)
Konceptům se říká Traversal a Prism.
Pro implementaci pokročilých čoček je (občas) potřeba použít ještěgeneričtější typy. Intuice z jednoduchého funktorového Lens ale platí.
227
![Page 322: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/322.jpg)
Víc optiky!
Problémy:
• allItems :: Lens [a]
• left :: Lens (Either a b)
Konceptům se říká Traversal a Prism.
Pro implementaci pokročilých čoček je (občas) potřeba použít ještěgeneričtější typy. Intuice z jednoduchého funktorového Lens ale platí.
227
![Page 323: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/323.jpg)
Víc optiky!
Problémy:
• allItems :: Lens [a]
• left :: Lens (Either a b)
Konceptům se říká Traversal a Prism.
Pro implementaci pokročilých čoček je (občas) potřeba použít ještěgeneričtější typy. Intuice z jednoduchého funktorového Lens ale platí.
227
![Page 324: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/324.jpg)
Traversal
Pokud chceme optiku aplikovat na víc věcí, musí funktor podporovatmožnost spojovat obaly. Tradičním řešením je Applicative:
data Two a = Two a a deriving Showtwo ff (Two a b) = Two 〈$〉 ff a 〈∗〉 ff b
Výsledky vypadají zajímavě:
a = Two (Two 1 2) (Two 3 4)
set two 5 a ; Two 5 5set (two · x) 5 a ; Two (Two 5 2) (Two 5 4)
set (x · two) 5 a ; Two (Two 5 5) (Two 3 4)
over (two · y) (+10) a ; Two (Two 1 12) (Two 3 14)
228
![Page 325: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/325.jpg)
:t view two
view two ::Monoid c⇒ Two c→ c
kde se tady vzal monoid?
228
![Page 326: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/326.jpg)
:t view two
view two ::Monoid c⇒ Two c→ c
kde se tady vzal monoid?
228
![Page 327: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/327.jpg)
view two :: Monoid c⇒ Two c→ c
Důvod je v definici aplikativní instance Const:
instance Monoid b⇒ Applicative (Const b)
Použití:
view two (Two (Sum 1) (Sum 2))
; Sum {getSum = 3}
view two (Two [1, 2] [3, 4])
; [1, 2, 3, 4]
229
![Page 328: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/328.jpg)
Traverzování
Překvapivě, traverse je traversal pro všechno traverzovatelné:
traverse :: (Applicative f, Traversable t)⇒(a→ f b)→ (t a→ f (t b))
(typ je jen o trochu košatější, než u Lens a b)
over (traverse · y) (+1) [Two 1 2, Two 3 4]
; [Two 1 3, Two 3 5]
listOf l = getConst · l (λx→ Const [x ])
listOf two $ Two (Two 1 2) (Two 3 4)
; [Two 1 2, Two 3 4]
listOf (two · y) $ Two (Two 1 2) (Two 3 4) ; [2, 4]
listOf (y · two) $ Two (Two 1 2) (Two 3 4) ; [3, 4]
230
![Page 329: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/329.jpg)
Traverzování
SQL cvičení:
ident f s = f signored f s = pure sfiltered cond f s = if cond s then f s else pure sover (two · two · filtered even) (‘div‘2) $ Two (Two 1 2) (Two 3 4)
; Two (Two 1 1) (Two 3 2)
231
![Page 330: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/330.jpg)
Iso
Iso je čočka měnící reprezentaci (název podle izomorfismu).
asString :: (Show a,Read a)⇒ Lens a StringasString ff a = fmap read $ ff (show a)
set (two · asString · traverse · filtered (≡ ’3’)) ’5’ $ Two 103 430; Two 105 450
(bez explicitního typu asString neví, že má vracet to samé a)
232
![Page 331: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/331.jpg)
Prism
Prism je speciální případ Traversal, který matchne maximálně jednuhodnotu.
• view nemusí nevyžadovat monoidnost, stačí preview sMaybe(implementace pomocí funktoru First)
• jde obrátit (review, re)
Praktická definice pro implementaci: Iso totální jen v jednom směru.
233
![Page 332: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/332.jpg)
Prism
preview _Right (Right 5) ; Just 5preview _Right (Left 5) ; Nothingview (re _Right) 3 ; Right 3review _Right 3 ; Right 3
preview (prefixed "tele") "telescope" ; Just "scope"preview (prefixed "tele") "orange" ; Nothingreview (prefixed "tele") "graph" ; "telegraph"
Intuice: Prism generalizuje datový konstruktor a pattern match.
234
![Page 333: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/333.jpg)
Lens library
Optika je implementovaná v Control.Lens. Občas stačí i Lens.Micro.
Bonusy:
• TemplateHaskell• Fajn operátory
235
![Page 334: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/334.jpg)
Lens library — TH
TemplateHaskellem je možné automaticky vyrobit optiku pro ADT:
{-# LANGUAGE TemplateHaskell #-}import Control.Lensdata Two a = Two {_x :: a, _y :: a} deriving ShowmakeLenses ” Twox :: Functor f ⇒ (a→ f a)→ Two a→ f (Two a)
y :: Functor f ⇒ (a→ f a)→ Two a→ f (Two a)
(podtržítka jsou konvence)
236
![Page 335: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/335.jpg)
Lens library — TH
Kolize jmen se řeší pomocí typových tříd:
{-# LANGUAGE TemplateHaskell #-}{-# LANGUAGE FlexibleInstances #-}{-# LANGUAGE FunctionalDependencies #-}import Control.Lensdata Two a = Two {_twoX :: a, _twoY :: a}makeFields ” Twodata Three a = Three {_threeX :: a, _threeY :: a, _threeZ :: a}makeFields ” Threex :: (Functor f,HasX s a)⇒ (a→ f a)→ s→ f s
(podtržítka s názvem konstruktoru jsou konvence)
237
![Page 336: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/336.jpg)
Operátory!
prefix infix Stateview ^.set .~ .=over %~ %=toListOf ^..preview ^?
+~, -~, *~ +=, -=, *=
Pomůcka: & je obrácený $.
238
![Page 337: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/337.jpg)
Operátory!
(0, 1, 0, 1, 0, 1) & _1 .˜ 7& _2 %˜ (5∗)& _3 .˜ (−1)
& _4 .˜ "orange"& _5 %˜ (2+)
& _6 %˜ (3∗)
; (7, 5,−1, "orange", 2, 3)
239
![Page 338: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/338.jpg)
Stringologie a formátování textu
![Page 339: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/339.jpg)
Text v Haskellu
• String• [Char] — obrovský overhead na písmeno (16-32B), každé písmeno je
boxed value, ...• každá položka seznamu je jeden nezávislý Unicode znak (tj. bez
normalizace)• pro zpracování většího množství textu je String pomalý
• ByteString• obdoba char*, implementačně cca. Vector Word8• žádný Unicode!• vektorová rychlost, vstup Attoparsecu
• Text• Unicode-aware (interně uloženo jako normalizované UTF)• interně to je Array-slice• poměrně malý overhead všech Stringových operací
240
![Page 340: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/340.jpg)
Text v Haskellu
• String• [Char] — obrovský overhead na písmeno (16-32B), každé písmeno je
boxed value, ...• každá položka seznamu je jeden nezávislý Unicode znak (tj. bez
normalizace)• pro zpracování většího množství textu je String pomalý
• ByteString• obdoba char*, implementačně cca. Vector Word8• žádný Unicode!• vektorová rychlost, vstup Attoparsecu
• Text• Unicode-aware (interně uloženo jako normalizované UTF)• interně to je Array-slice• poměrně malý overhead všech Stringových operací
240
![Page 341: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/341.jpg)
Text v Haskellu
• String• [Char] — obrovský overhead na písmeno (16-32B), každé písmeno je
boxed value, ...• každá položka seznamu je jeden nezávislý Unicode znak (tj. bez
normalizace)• pro zpracování většího množství textu je String pomalý
• ByteString• obdoba char*, implementačně cca. Vector Word8• žádný Unicode!• vektorová rychlost, vstup Attoparsecu
• Text• Unicode-aware (interně uloženo jako normalizované UTF)• interně to je Array-slice• poměrně malý overhead všech Stringových operací
240
![Page 342: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/342.jpg)
Text v Haskellu
• String• [Char] — obrovský overhead na písmeno (16-32B), každé písmeno je
boxed value, ...• každá položka seznamu je jeden nezávislý Unicode znak (tj. bez
normalizace)• pro zpracování většího množství textu je String pomalý
• ByteString• obdoba char*, implementačně cca. Vector Word8• žádný Unicode!• vektorová rychlost, vstup Attoparsecu
• Text• Unicode-aware (interně uloženo jako normalizované UTF)• interně to je Array-slice• poměrně malý overhead všech Stringových operací
240
![Page 343: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/343.jpg)
IsString
Protože je těžké odhadnout, v jakém formátu chce programátor mít literály,existuje třída IsString:
{-# LANGUAGE OverloadedStrings #-}class IsString a wherefromString :: String→ a
"ahoj" :: IsString s⇒ s"ahoj" :: Text ; OK"ahoj" :: ByteString ; OK
241
![Page 344: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/344.jpg)
ByteString
Konverze:
import Data.ByteString as BB.pack :: [Word8]→ ByteStringB.unpack :: ByteString→ [Word8]
Postupná konstrukce:
B.cons :: Word8→ ByteString→ ByteStringB.snoc :: ByteString→ Word8→ ByteStringB.uncons :: ByteString→ Maybe (Word8,ByteString)
B.unsnoc :: ByteString→ Maybe (ByteString,Word8)
242
![Page 345: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/345.jpg)
ByteString
I/O:
B.getLine :: IO ByteStringB.hGetLine :: Handle→ IO ByteStringB.hPutStr :: Handle→ ByteString→ IO ()
B.hGetContents :: Handle→ IO ByteStringB.hGet :: Handle→ Int→ IO ByteStringB.hPut :: Handle→ ByteString→ IO ()
apod.
243
![Page 346: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/346.jpg)
UTF
Obsah ByteStringu je pro převedení na String nebo Text potřeba dekódovat.(Unicode jde kódovat jako UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, . . . ,ztrátově jako Latin1, ISO8859-1, Codepage 1250, KOI-8, . . . )
import Data.Text.EncodingdecodeUtf8 :: ByteString→ TextdecodeUtf16BE :: ByteString→ TextdecodeUtf32LE :: ByteString→ TextencodeUtf8 :: Text→ ByteStringencodeUtf16LE :: Text→ ByteString
244
![Page 347: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/347.jpg)
Text
Text je hodně optimalizovaný (většina funkcí se fůzuje a/nebo zmizí).
import Data.Text as TT.pack :: String→ TextT.unpack :: Text→ String
. . .(cons, snoc, append, take, takeEnd, intercalate, toLower, justifyLeft,splitOn, ...)
245
![Page 348: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/348.jpg)
Text
Text je hodně optimalizovaný (většina funkcí se fůzuje a/nebo zmizí).
import Data.Text as TT.pack :: String→ TextT.unpack :: Text→ String
. . .(cons, snoc, append, take, takeEnd, intercalate, toLower, justifyLeft,splitOn, ...)
245
![Page 349: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/349.jpg)
Jak si vybrat?
situace řešení
Potřebuju rychlost, obsah vstupu interpretujuvlastním kódem
ByteString
Používám AttoParsec ByteString
Mám nekonečnou větu plnou nerozhodnutelnýchpísmen
String
Aplikace je jednoduchá a stringový overhead jeskoro nulový
String
Všechny ostatní případy Text
246
![Page 350: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/350.jpg)
Pravda o Pretty-Printingu
Show není pretty-printing!
246
![Page 351: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/351.jpg)
Pravda o Pretty-Printingu
Show není pretty-printing!
246
![Page 352: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/352.jpg)
Text.PrettyPrint
Pretty-printing se od Show-ování liší v několika podstatných ohledech:
• výstup není potřeba parsovat (nemusí obsahovat detaily)• výstup může obsahovat redundanci• občas je potřeba odsazovat a zarovnávat
Haskellový přístup:
import Text.PrettyPrintrenderStyle (style { lineLength = 80}) :: Doc→ String
247
![Page 353: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/353.jpg)
Text.PrettyPrint
Pretty-printing se od Show-ování liší v několika podstatných ohledech:
• výstup není potřeba parsovat (nemusí obsahovat detaily)• výstup může obsahovat redundanci• občas je potřeba odsazovat a zarovnávat
Haskellový přístup:
import Text.PrettyPrintrenderStyle (style { lineLength = 80}) :: Doc→ String
247
![Page 354: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/354.jpg)
Text.PrettyPrint
Pretty-printing se od Show-ování liší v několika podstatných ohledech:
• výstup není potřeba parsovat (nemusí obsahovat detaily)• výstup může obsahovat redundanci• občas je potřeba odsazovat a zarovnávat
Haskellový přístup:
import Text.PrettyPrintrenderStyle (style { lineLength = 80}) :: Doc→ String
247
![Page 355: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/355.jpg)
Text.PrettyPrint
Doc je abstrakce pro různě pospojovaná políčka textu (podobně jakoTEX-ové vlisty/hlisty).
empty :: Doctext :: String→ DocsizedText :: Int→ String→ Docint :: Int→ Docfloat :: Float→ Doc
248
![Page 356: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/356.jpg)
Text.PrettyPrint
Dekorace:
semi, equals, lparen, rparen, comma, colon, space, ... :: Docparens, brackets, quotes, ... :: Doc→ Docpunctuate :: Doc→ [Doc ]→ [Doc ]
249
![Page 357: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/357.jpg)
Text.PrettyPrint
Lepení:
(�) :: Doc→ Doc→ Doc -- vedle(〈+〉) :: Doc→ Doc→ Doc -- vedle s mezerou (nějakou)($$) :: Doc→ Doc→ Doc -- nad sebou($+$) :: Doc→ Doc→ Doc -- nad sebou bez nestingunest :: Int→ Doc→ Doc -- odsazení
Seznamové verze: hcat, hsep, vcat, vsep
Chytré verze (v/h): cat, sep
Odstavcové verze: fcat, fsep
250
![Page 358: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/358.jpg)
Text.PrettyPrint — demo
import Text.PrettyPrintdata Scheme = Ident String | Number Int | Seq [Scheme]
class PDoc a wherepdoc :: a→ Doc
ppshow :: PDoc a⇒ a→ Stringppshow = renderStyle (style { lineLength = 80}) · pdocinstance PDoc Scheme wherepdoc (Ident a) = text apdoc (Number i) = int ipdoc (Seq xs) = parens $ sep (map pdoc xs)
251
![Page 359: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/359.jpg)
Text.PrettyPrint — demo
short k = Seq $ Ident "*" : map Number [k . . k + 3]
long = Seq $ Ident "+" : map short [1 . . 10]
main = putStrLn · ppshow $ Seq [ Ident "factorial", long ]
(factorial(+(* 1 2 3 4)(* 2 3 4 5)(* 3 4 5 6)(* 4 5 6 7)(* 5 6 7 8)(* 6 7 8 9)(* 7 8 9 10)(* 8 9 10 11)(* 9 10 11 12)(* 10 11 12 13)))
252
![Page 360: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/360.jpg)
Text.PrettyPrint — demo
pdoc (Seq [ ]) = parens emptypdoc (Seq (x : xs)) = parens $ pdoc x 〈+〉 sep (map pdoc xs)
(factorial (+ (* 1 2 3 4)(* 2 3 4 5)(* 3 4 5 6)(* 4 5 6 7)(* 5 6 7 8)(* 6 7 8 9)(* 7 8 9 10)(* 8 9 10 11)(* 9 10 11 12)(* 10 11 12 13)))
253
![Page 361: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/361.jpg)
IO!
![Page 362: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/362.jpg)
Co ještě umí run-time Haskellu?
• UNIX-like soubory a síťovou komunikaci• konkurentní výpočet programu a synchronizaci• paralelní výpočet programu• reference a pointery• FFI
254
![Page 363: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/363.jpg)
Komunikace uživatele s programem
• Proměnlivé prostředí (‘env’)
import System.EnvironmentgetEnv :: IO StringlookupEnv "PATH" :: IO (Maybe String)
getEnvironment :: IO [(String, String)]
• Parametry z příkazového řádku
getArgs :: IO [String ]
getProgName :: IO StringgetExecutablePath :: IO FilePath
255
![Page 364: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/364.jpg)
Komunikace uživatele s programem
• Proměnlivé prostředí (‘env’)
import System.EnvironmentgetEnv :: IO StringlookupEnv "PATH" :: IO (Maybe String)
getEnvironment :: IO [(String, String)]
• Parametry z příkazového řádku
getArgs :: IO [String ]
getProgName :: IO StringgetExecutablePath :: IO FilePath
255
![Page 365: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/365.jpg)
Komunikace uživatele s programem
• exit-code
import System.Exitdie "sorry jako" :: IO aexitWith (exitSuccess) :: IO aexitWith (exitFailure 3) :: IO a
• čtení a zápis z/do souborových deskriptorů
import System.IOopenFile "test" WriteMode :: IO HandlehClose h :: IO ()
hGetChar h :: IO CharhPutChar h ’c’ :: IO ()
256
![Page 366: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/366.jpg)
Komunikace uživatele s programem
• exit-code
import System.Exitdie "sorry jako" :: IO aexitWith (exitSuccess) :: IO aexitWith (exitFailure 3) :: IO a
• čtení a zápis z/do souborových deskriptorů
import System.IOopenFile "test" WriteMode :: IO HandlehClose h :: IO ()
hGetChar h :: IO CharhPutChar h ’c’ :: IO ()
256
![Page 367: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/367.jpg)
Komunikace uživatele s programem
• posílat a chytat signály
import System.Posix.SignalsraiseSignal sigSTOP :: IO ()
signalProcess sigKILL 1 :: IO ()
data Handler = Default | Ignore| Catch (IO ()) | CatchOnce (IO ()) | ...
installHandler sigTERM(Catch $ putStrLn "nope")
Nothing:: IO Handler
(většina ostatních nízkoúrovňových věcí je v balíčku unix)
257
![Page 368: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/368.jpg)
Komunikace uživatele s programem
• posílat a chytat signály
import System.Posix.SignalsraiseSignal sigSTOP :: IO ()
signalProcess sigKILL 1 :: IO ()
data Handler = Default | Ignore| Catch (IO ()) | CatchOnce (IO ()) | ...
installHandler sigTERM(Catch $ putStrLn "nope")
Nothing:: IO Handler
(většina ostatních nízkoúrovňových věcí je v balíčku unix)257
![Page 369: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/369.jpg)
Jak se pozná kvalitní UNIXový program?
Vypisuje --help související s realitou.
257
![Page 370: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/370.jpg)
Jak se pozná kvalitní UNIXový program?
Vypisuje --help související s realitou.
257
![Page 371: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/371.jpg)
optparse-applicative
Abstrakce: Volitelné vlastnosti parametrů budeme popisovat jako monoid.Parametry pak aplikativně spojíme do velké struktury.
import Options.Applicativeimport Data.Semigroup ((�))
theOption :: Parser BooltheOption = switch $ long "good"
� short ’g’� help "Should it be really good?"
optInfo = info (helper 〈∗〉 theOption)
$ progDesc "good shows current level of goodness"� header "A program that shows if it’s good."� footer "See more information on www.good.program.hu"
258
![Page 372: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/372.jpg)
optparse-applicative
Abstrakce: Volitelné vlastnosti parametrů budeme popisovat jako monoid.Parametry pak aplikativně spojíme do velké struktury.
import Options.Applicativeimport Data.Semigroup ((�))
theOption :: Parser BooltheOption = switch $ long "good"
� short ’g’� help "Should it be really good?"
optInfo = info (helper 〈∗〉 theOption)
$ progDesc "good shows current level of goodness"� header "A program that shows if it’s good."� footer "See more information on www.good.program.hu"
258
![Page 373: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/373.jpg)
optparse-applicative
Abstrakce: Volitelné vlastnosti parametrů budeme popisovat jako monoid.Parametry pak aplikativně spojíme do velké struktury.
import Options.Applicativeimport Data.Semigroup ((�))
theOption :: Parser BooltheOption = switch $ long "good"
� short ’g’� help "Should it be really good?"
optInfo = info (helper 〈∗〉 theOption)
$ progDesc "good shows current level of goodness"� header "A program that shows if it’s good."� footer "See more information on www.good.program.hu"
258
![Page 374: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/374.jpg)
optparse-applicative
Abstrakce: Volitelné vlastnosti parametrů budeme popisovat jako monoid.Parametry pak aplikativně spojíme do velké struktury.
import Options.Applicativeimport Data.Semigroup ((�))
theOption :: Parser BooltheOption = switch $ long "good"
� short ’g’� help "Should it be really good?"
optInfo = info (helper 〈∗〉 theOption)
$ progDesc "good shows current level of goodness"� header "A program that shows if it’s good."� footer "See more information on www.good.program.hu"
258
![Page 375: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/375.jpg)
optparse-applicative
Abstrakce: Volitelné vlastnosti parametrů budeme popisovat jako monoid.Parametry pak aplikativně spojíme do velké struktury.
import Options.Applicativeimport Data.Semigroup ((�))
theOption :: Parser BooltheOption = switch $ long "good"
� short ’g’� help "Should it be really good?"
optInfo = info (helper 〈∗〉 theOption)
$ progDesc "good shows current level of goodness"� header "A program that shows if it’s good."� footer "See more information on www.good.program.hu"
258
![Page 376: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/376.jpg)
optparse-applicative
Abstrakce: Volitelné vlastnosti parametrů budeme popisovat jako monoid.Parametry pak aplikativně spojíme do velké struktury.
import Options.Applicativeimport Data.Semigroup ((�))
theOption :: Parser BooltheOption = switch $ long "good"
� short ’g’� help "Should it be really good?"
optInfo = info (helper 〈∗〉 theOption)
$ progDesc "good shows current level of goodness"� header "A program that shows if it’s good."� footer "See more information on www.good.program.hu"
258
![Page 377: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/377.jpg)
optparse-applicative
main = do opt← execParser $ optInfoputStrLn $ if opt
then "yeah it’s good"else "not good at all!"
$ ./goodnot good at all!$ ./good -xInvalid option ‘-x’
Usage: ./good [-g|--good]$ ./good -gyeah it’s good
259
![Page 378: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/378.jpg)
optparse-applicative
main = do opt← execParser $ optInfoputStrLn $ if opt
then "yeah it’s good"else "not good at all!"
$ ./goodnot good at all!$ ./good -xInvalid option ‘-x’
Usage: ./good [-g|--good]$ ./good -gyeah it’s good
259
![Page 379: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/379.jpg)
optparse-applicative
$ ./good -hA program that shows if it’s good.
Usage: good [-g|--good]good shows current level of goodness
Available options:-h,--help Show this help text-g,--good Should it be really good?
See more information on www.good.program.hu
260
![Page 380: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/380.jpg)
optparse-applicative
• Stringy
optOutput = strOption$ long "output"� short ’o’�metavar "FILE"� value "out.txt"� showDefault� help "Write output to FILE"
• Integery
optLevel = option$ long "level"� short ’l’� help "Level of whatever"� value 5 261
![Page 381: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/381.jpg)
optparse-applicative
• Kombinace (produkt)
data CmdLineOpts = CmdLineOpts { level :: Int,output :: String}
allOptions = CmdLineOpts 〈$〉 optLevel 〈∗〉 optOutput
• Kombinace alternativ
data OptionalOutput = FileOutput String | StdOutputoptionOptionalOutput = FileOutput 〈$〉 optOutput〈|〉 flag′ StdOutput (long "stdout"
� help "write to stdout")
262
![Page 382: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/382.jpg)
RTS
Run-time systém nad nízkoúrovňovým systémovým interfacem provozujevlastní event loop.
• Umožňuje velmi efektivní konkurentní programování (“green threads”)• Zabraňuje potížím s pollováním bez overheadu vláken• Poskytuje C-like sdílení zapisovatelných objektů
263
![Page 383: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/383.jpg)
ForkIO
import Control.ConcurrentforkIO :: IO ()→ IO ThreadID
forkIO provede IO akci paralelně s volající monádou.
Výhoda: Lehká vlákna nemají žádný overhead.
264
![Page 384: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/384.jpg)
Konkurentní programování
Pro komunikaci mezi vlákny máme (mimo jiné)MVar:
import Control.Concurrent.MVarnewEmptyMVar :: IO (MVar a)
newMVar :: a→ IO (MVar a)
takeMVar :: MVar a→ IO aputMVar :: MVar a→ a→ IO ()
readMVar :: MVar a→ IO aswapMVar :: MVar a→ a→ IO a
MVar může být plná nebo prázdná, put/take jsou blokující.
265
![Page 385: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/385.jpg)
Konkurentní programování — příklad
import Control.Monadimport Control.Concurrentimport Control.Concurrent.MVarmain = dokolik ← readLn :: IO Intcom← newEmptyMVarforkIO $ doforM_ [1 . . kolik ] $ λi→putMVar com i >> threadDelay 333333
forM_ [1 . . kolik ] $ λi→putMVar com (kolik − i)>> threadDelay 333333
let loop = do a← takeMVar comwhen (a> 0) $ print a>> loop
loop 266
![Page 386: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/386.jpg)
Konkurentní programování — TCP server
import Control.Concurrentimport Control.Exception (bracket)import Control.Monad (forever, void)
import Network.Socketmain =
withSocketsDo $ docounter ← newMVar 0bracket open close (serverLoop counter)
where...
267
![Page 387: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/387.jpg)
Konkurentní programování — TCP server
import Control.Concurrentimport Control.Exception (bracket)import Control.Monad (forever, void)
import Network.Socketmain =
withSocketsDo $ docounter ← newMVar 0bracket open close (serverLoop counter)
where...
267
![Page 388: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/388.jpg)
Konkurentní programování — TCP server
import Control.Concurrentimport Control.Exception (bracket)import Control.Monad (forever, void)
import Network.Socketmain =
withSocketsDo $ docounter ← newMVar 0bracket open close (serverLoop counter)
where...
267
![Page 389: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/389.jpg)
Konkurentní programování — TCP server
open = dosock ← socket AF_INET Stream defaultProtocolsetSocketOption sock ReuseAddr 1bind sock $ SockAddrInet 8080 0setCloseOnExecIfNeeded $ fdSocket socklisten sock 16return sock
268
![Page 390: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/390.jpg)
Konkurentní programování — TCP server
open = dosock ← socket AF_INET Stream defaultProtocolsetSocketOption sock ReuseAddr 1bind sock $ SockAddrInet 8080 0setCloseOnExecIfNeeded $ fdSocket socklisten sock 16return sock
268
![Page 391: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/391.jpg)
Konkurentní programování — TCP server
open = dosock ← socket AF_INET Stream defaultProtocolsetSocketOption sock ReuseAddr 1bind sock $ SockAddrInet 8080 0setCloseOnExecIfNeeded $ fdSocket socklisten sock 16return sock
268
![Page 392: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/392.jpg)
Konkurentní programování — TCP server
serverLoop counter sock =
forever $ do(conn, peer)← accept sockputStrLn $ "client: " ++ show peervoid $ forkFinally (talk counter conn)
(\_→ close conn)
269
![Page 393: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/393.jpg)
Konkurentní programování — TCP server
serverLoop counter sock =
forever $ do(conn, peer)← accept sockputStrLn $ "client: " ++ show peervoid $ forkFinally (talk counter conn)
(\_→ close conn)
269
![Page 394: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/394.jpg)
Konkurentní programování — TCP server
serverLoop counter sock =
forever $ do(conn, peer)← accept sockputStrLn $ "client: " ++ show peervoid $ forkFinally (talk counter conn)
(\_→ close conn)
269
![Page 395: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/395.jpg)
Konkurentní programování — TCP server
serverLoop counter sock =
forever $ do(conn, peer)← accept sockputStrLn $ "client: " ++ show peervoid $ forkFinally (talk counter conn)
(\_→ close conn)
269
![Page 396: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/396.jpg)
Konkurentní programování — TCP server
talk counter conn = domsg← words 〈$〉 recv conn 1024 -- String!putStrLn $ "Request: " ++ show msgcase msg of"GET": _→ doctr ← takeMVar counterputMVar counter (ctr + 1)
send conn $
"HTTP/1.0 200 OK\n" ++
"Content-type: text/plain\n\n" ++
"Hello, " ++ show ctr→ send conn "HTTP 400 bad request\n\n"
270
![Page 397: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/397.jpg)
Konkurentní programování — TCP server
talk counter conn = domsg← words 〈$〉 recv conn 1024 -- String!putStrLn $ "Request: " ++ show msgcase msg of"GET": _→ doctr ← takeMVar counterputMVar counter (ctr + 1)
send conn $
"HTTP/1.0 200 OK\n" ++
"Content-type: text/plain\n\n" ++
"Hello, " ++ show ctr→ send conn "HTTP 400 bad request\n\n"
270
![Page 398: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/398.jpg)
Konkurentní programování — TCP server
talk counter conn = domsg← words 〈$〉 recv conn 1024 -- String!putStrLn $ "Request: " ++ show msgcase msg of"GET": _→ doctr ← takeMVar counterputMVar counter (ctr + 1)
send conn $
"HTTP/1.0 200 OK\n" ++
"Content-type: text/plain\n\n" ++
"Hello, " ++ show ctr→ send conn "HTTP 400 bad request\n\n"
270
![Page 399: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/399.jpg)
Konkurentní programování — TCP server
talk counter conn = domsg← words 〈$〉 recv conn 1024 -- String!putStrLn $ "Request: " ++ show msgcase msg of"GET": _→ doctr ← takeMVar counterputMVar counter (ctr + 1)
send conn $
"HTTP/1.0 200 OK\n" ++
"Content-type: text/plain\n\n" ++
"Hello, " ++ show ctr→ send conn "HTTP 400 bad request\n\n"
270
![Page 400: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/400.jpg)
IO Bonusy
OverheadMVar je moc velký/zbytečný
• TVar (neprázdná proměnná, atomické operace nad STM)• IORef (neprázdná proměnná)• Ptr (ošklivá Cčková reference na P.O.D. bez GC)
STM je Software Transactional Memory monad — poskytuje serializovanýpřístup k paměti sdílené mezi vlákny.
271
![Page 401: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/401.jpg)
FFI
Když je potřeba sáhnout na dno, Haskell podporuje přímé napojení nasystémový C-style kód pomocí FFI.
Typické použití:
• Obalování systémových API• Obalování Cčkových knihoven (‘bindings’)• Drcení čísel
272
![Page 402: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/402.jpg)
FFI
FFI má 2 módy použití:
import • Cčkový .h a .c soubor se automaticky skompilují aslinkují s programem
• funkce lze popsat jako IO akce, i jako čisté funkce• typy parametrů se mapují z primitivních haskellových
typůexport • export haskellové funkce vygeneruje .h
• odpovídající symbol je ve skompilovaném .o
273
![Page 403: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/403.jpg)
FFI — import
Haskell:
{-# INCLUDE "rawread.h" #-}{-# LANGUAGE ForeignFunctionInterface #-}import Foreign.Cforeign import ccall "raw_read" rawRead :: Word→ IO Wordmain = rawRead 0>>= print
rawread.h: int64_t raw_read(int64_t);
rawread.c: (BONUS: skoro validní použití reinterpret_cast)
int64_t raw_read(int64_t addr) {int64_t* ptr=(int64_t*)addr;return *ptr;
} 274
![Page 404: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/404.jpg)
FFI — import
Haskell:
{-# INCLUDE "rawread.h" #-}{-# LANGUAGE ForeignFunctionInterface #-}import Foreign.Cforeign import ccall "raw_read" rawRead :: Word→ IO Wordmain = rawRead 0>>= print
rawread.h: int64_t raw_read(int64_t);
rawread.c: (BONUS: skoro validní použití reinterpret_cast)
int64_t raw_read(int64_t addr) {int64_t* ptr=(int64_t*)addr;return *ptr;
} 274
![Page 405: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/405.jpg)
FFI — export
Factorial.hs:
import Foreign.Cforeign export ccall "fact" factorial :: Int→ Intfactorial n = product [1 . . n]
factorial.c:
#include "Factorial_stub.h"void someF() {
printf("%d\n", fact(5));}
275
![Page 406: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/406.jpg)
Paralelní vyhodnocování
Paralelizace Haskellu je (technicky) celkem jednoduchá
• Většina jevů je bez efektů• RTS umí vlastní scheduling ‘zadarmo’• GC je celkem moderní a víc vláken zvládá dobře
(narozdíl od Javy, C# a Pythonu)
Implementace:
par :: a→ b→ b
“Indicates that it may be beneficial to evaluate the first argument in parallelwith the second. Returns the value of the second argument.
a ‘par‘ b is exactly equivalent semantically to b.”
276
![Page 407: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/407.jpg)
Paralelní vyhodnocování
Paralelizace Haskellu je (technicky) celkem jednoduchá
• Většina jevů je bez efektů• RTS umí vlastní scheduling ‘zadarmo’• GC je celkem moderní a víc vláken zvládá dobře
(narozdíl od Javy, C# a Pythonu)
Implementace:
par :: a→ b→ b
“Indicates that it may be beneficial to evaluate the first argument in parallelwith the second. Returns the value of the second argument.
a ‘par‘ b is exactly equivalent semantically to b.”
276
![Page 408: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/408.jpg)
Paralelní programování
hardFunction = letfirstHalf = ...
secondHalf = ...
in firstHalf ‘par‘ secondHalf ‘par‘ firstHalf + secondHalf
Kompilace: ghc -threaded -rtsopts hard.hs
Spuštění pro 16 jader: ./hard +RTS -N16
Nevýhoda:
Pokud paralelismem chceme dosáhnout rychlosti, je lepšíprogram napsat v C a volat přes FFI. (paralelně)
277
![Page 409: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/409.jpg)
Paralelní programování
hardFunction = letfirstHalf = ...
secondHalf = ...
in firstHalf ‘par‘ secondHalf ‘par‘ firstHalf + secondHalf
Kompilace: ghc -threaded -rtsopts hard.hs
Spuštění pro 16 jader: ./hard +RTS -N16
Nevýhoda: Pokud paralelismem chceme dosáhnout rychlosti, je lepšíprogram napsat v C a volat přes FFI. (paralelně)
277
![Page 410: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/410.jpg)
Paralelní programování
Lepší kontrola nad prováděním kódu:
import Control.Parallel.Strategies
Akcelerace automatickým přeložením programu do paralelního SIMD neboCUDA:
import Data.Array.Acceleratedotp :: Acc (Vector Float)→ Acc (Vector Float)→ Acc (Scalar Float)dotp xs ys = fold (+) 0 (zipWith (∗) xs ys)
Numerické výpočty s možností paralelizace:
import Data.Array.Repa
�Parallel and concurrent programming in Haskell: Techniques for multicoreand multithreaded programming (Simon Marlow, 2013)
278
![Page 411: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/411.jpg)
Paralelní programování
Lepší kontrola nad prováděním kódu:
import Control.Parallel.Strategies
Akcelerace automatickým přeložením programu do paralelního SIMD neboCUDA:
import Data.Array.Acceleratedotp :: Acc (Vector Float)→ Acc (Vector Float)→ Acc (Scalar Float)dotp xs ys = fold (+) 0 (zipWith (∗) xs ys)
Numerické výpočty s možností paralelizace:
import Data.Array.Repa
�Parallel and concurrent programming in Haskell: Techniques for multicoreand multithreaded programming (Simon Marlow, 2013)
278
![Page 412: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/412.jpg)
Paralelní programování
Lepší kontrola nad prováděním kódu:
import Control.Parallel.Strategies
Akcelerace automatickým přeložením programu do paralelního SIMD neboCUDA:
import Data.Array.Acceleratedotp :: Acc (Vector Float)→ Acc (Vector Float)→ Acc (Scalar Float)dotp xs ys = fold (+) 0 (zipWith (∗) xs ys)
Numerické výpočty s možností paralelizace:
import Data.Array.Repa
�Parallel and concurrent programming in Haskell: Techniques for multicoreand multithreaded programming (Simon Marlow, 2013)
278
![Page 413: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/413.jpg)
Paralelní programování
Lepší kontrola nad prováděním kódu:
import Control.Parallel.Strategies
Akcelerace automatickým přeložením programu do paralelního SIMD neboCUDA:
import Data.Array.Acceleratedotp :: Acc (Vector Float)→ Acc (Vector Float)→ Acc (Scalar Float)dotp xs ys = fold (+) 0 (zipWith (∗) xs ys)
Numerické výpočty s možností paralelizace:
import Data.Array.Repa
�Parallel and concurrent programming in Haskell: Techniques for multicoreand multithreaded programming (Simon Marlow, 2013)
278
![Page 414: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/414.jpg)
Paralelní programování
Lepší kontrola nad prováděním kódu:
import Control.Parallel.Strategies
Akcelerace automatickým přeložením programu do paralelního SIMD neboCUDA:
import Data.Array.Acceleratedotp :: Acc (Vector Float)→ Acc (Vector Float)→ Acc (Scalar Float)dotp xs ys = fold (+) 0 (zipWith (∗) xs ys)
Numerické výpočty s možností paralelizace:
import Data.Array.Repa
�Parallel and concurrent programming in Haskell: Techniques for multicoreand multithreaded programming (Simon Marlow, 2013)
278
![Page 415: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/415.jpg)
Transformujeme monády
![Page 416: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/416.jpg)
Motivace
Co když chceme monádu, která umí:
• State (put, get, ...) a IO (print)?• Parsec + IO?• IO + Either?• State + IO + seznamový nedeterminismus? (a.k.a. prolog)
Software engineering: Naprogramujeme všechny kombinace!
279
![Page 417: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/417.jpg)
Motivace
Co když chceme monádu, která umí:
• State (put, get, ...) a IO (print)?• Parsec + IO?• IO + Either?• State + IO + seznamový nedeterminismus? (a.k.a. prolog)
Software engineering: Naprogramujeme všechny kombinace!
279
![Page 418: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/418.jpg)
Při výrobě nové monády dostanu 2n nových kombinací!
279
![Page 419: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/419.jpg)
Lepší nápad
Nešly by existující monády kombinovat nějak jednoduše?
Příklad IO s možností selhat (Maybe + IO):
newtype MaybeIO a =
MaybeIO {runMaybeIO :: IO (Maybe a)}
instance Functor MaybeIO wherefmap f (MaybeIO m) = MaybeIO $ fmap (fmap f) m
instance Applicative MaybeIO wherepure = MaybeIO · pure · JustMaybeIO a 〈∗〉MaybeIO b = MaybeIO $
a>>= maybe (return Nothing)
((〈$〉b) · fmap)
NB.: aplikativní instance je mírně asymetrická.
280
![Page 420: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/420.jpg)
instance Monad MaybeIO wherereturn = pureMaybeIO a>>= f = MaybeIO $
a>>= maybe (return Nothing)
(runMaybeIO · f)
281
![Page 421: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/421.jpg)
MaybeIO
Jak použít MaybeIO?
runMaybeIO :: MaybeIO a→ IO (Maybe a)
Jak vyvolat IO akci:
liftIO :: IO a→ MaybeIO aliftIO io = MaybeIO (return 〈$〉 io)
Jak vyvolat Maybe ‘akci’:
failMIO :: MaybeIO afailMIO = MaybeIO (return Nothing)
282
![Page 422: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/422.jpg)
Demo
io = liftIOmain = runMaybeIO $ doio $ putStrLn "daj cislo"a← io (readLn :: IO Float)if a< 0 then failMIOelse io $ putStrLn "jde odmocnit!"
io · print $ sqrt a
283
![Page 423: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/423.jpg)
Transformer
Pozorování: Nepoužili jsme nic specifického pro IO! Můžeme generalizovatpro všechny “obalené” monády.
newtype MaybeT m a =
MaybeT {runMaybeT :: m (Maybe a)}
instance Functor m⇒ Functor (MaybeT m) wherefmap f = MaybeT · fmap (fmap f) · runMaybeT
instance Monad m⇒ Applicative (MaybeT m) wherepure = MaybeT · pure · JustMaybeT a 〈∗〉MaybeT b = MaybeT $
a>>= maybe (return Nothing)
((〈$〉b) · fmap)
284
![Page 424: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/424.jpg)
Transformer!
instance Monad m⇒ Applicative (MaybeT m) wherereturn = pureMaybeT a>>= f = MaybeT $
a>>= maybe (return Nothing)
(runMaybeIO · f)
285
![Page 425: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/425.jpg)
Generický lift
class MonadTrans t wherelift :: Monad m⇒ m a→ t m a
instance MonadTrans MaybeT wherelift = MaybeT · fmap Just
286
![Page 426: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/426.jpg)
Příjemnější operace
Pamatovat si o kolik úrovní níž je v monádovém stacku zastrčené IO: nuda.
class Monad m⇒ MonadIO m whereliftIO :: IO a→ m a
instance MonadIO IO whereliftIO = id
instance (MonadIO m,MonadTrans t)⇒ MonadIO (t m) where
liftIO = lift · liftIO
(tato implementace je naivní a ilustrativní)
Zjednodušení: putStrLn :: MonadIO m⇒ String→ m ()
287
![Page 427: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/427.jpg)
Ještě příjemnější operace
Samozřejmě existují StateT, ReaderT, EitherT, . . .
Operace pro práci s monádou jsou typicky přetížené i pro transformovanévarianty, např v knihovně mtl:
class Monad m⇒ MonadState s m | m→ s whereget :: m sput :: s→ m ()
state :: (s→ (a, s))→ m aclass (Monoid w,Monad m)
⇒ MonadWriter w m | m→ w wheretell :: w→ m ()
class Monad m⇒ MonadError e m | m→ e wherethrowError :: e→ m acatchError :: m a→ (e→ m a)→ m a
288
![Page 428: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/428.jpg)
Knihovní transformery a monády
Typické knihovny na monádové stacky jsou 2:
• mtl — starší, postavená z víceparametrových typových tříd• transformers — novější, tosamé vyrobené z typových rodin, navíc je
Haskell98
Doporučení (2018): Pokud možno, používejte transformers.
289
![Page 429: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/429.jpg)
Běžné transformery
• Identity — nedělá nic, ale hodí se např. na odstraňování speciálníchpřípadů:NejakaMonada = NejakaMonadaT Identity
• MaybeT, EitherT (není vhodné na chyby!)• ExceptT (ErrorT je deprecated)• StateT — stavový výpočet• ReaderT — výpočet s globálním prostředím, ask• WriterT — vypočet konstruuje monoid, tell• RWST — ReaderWriterStateT (poměrně typické kombo)• ListT — funguje, ale má trochu nevhodný systém selhávání
290
![Page 430: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/430.jpg)
Reader trivia
InstanceMonad (Reader r) je prakticky ekvivalentníMonad ((→) r).
O jakémkoliv rozšiřování parametrů se často mluví jako oReaderu.
Human-style: λx→ (f x, g x)
Reader-style: liftA2 (, ) f g
290
![Page 431: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/431.jpg)
Reader trivia
InstanceMonad (Reader r) je prakticky ekvivalentníMonad ((→) r).
O jakémkoliv rozšiřování parametrů se často mluví jako oReaderu.
Human-style: λx→ (f x, g x)
Reader-style: liftA2 (, ) f g
290
![Page 432: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/432.jpg)
Užitečné funktory
• Identity• Const c• Compose f g — 2 (aplikativní) funktory v jednom• Sum, Product• Reverse — obrací folding a traverzování• Backwards — obrací pořadí operací u (〈∗〉)
291
![Page 433: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/433.jpg)
Jak na backtracking?
Možnost 0: Alternative(typicky pro parsery)
Možnost 1: MonadPlus
class (Alternative m,Monad m)⇒ MonadPlus m wheremzero :: m amplus :: m a→ m a→ m a
mplus se díky požadavku na monadičnost může chovat podstatně slušněji.
292
![Page 434: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/434.jpg)
Jak na backtracking?
Možnost 2: LogicT
class MonadPlus m⇒ MonadLogic m wheremsplit :: m a→ m (Maybe (a,m a)) -- první výsledekifte :: m a→ (a→ m b)→ m b→ m b -- soft cutonce :: m a→ m a -- hard cut(>>−) :: m a→ (a→ m b)→ m b -- férová konjunkceinterleave :: m a→ m a→ m a -- disjunkce
Zbytek:
• (>>=) je prologová čárka• guard funguje jako pro seznamy• ‘mplus‘ je prologový středník
293
![Page 435: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/435.jpg)
CPS
Continuation passing style je metoda programování bez ‘vracení’ hodnot.
Normální kód: f x = do {r ← g x; return (2 ∗ r); }
CPS-style kód: f x cont = g x (λr → cont (2 ∗ r))
Odpovídající Cont a ContT jdou použít (mimo jiné) k výraznému ovlivňovánícontrol-flow.
294
![Page 436: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/436.jpg)
CPS
import Control.Monadimport Control.Monad.Trans.Classimport Control.Monad.Trans.ContgetCC = callCC (return · fix)
main = flip runContT return $ dolift $ putStrLn "nazdar!"restart← getCClift $ putStrLn "hadej cislo"a← lift (readLn :: IO Int)unless (a ≡ 42) restartlift $ putStrLn "konecne dobre!"
295
![Page 437: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/437.jpg)
Grafické knihovny
![Page 438: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/438.jpg)
Jak na grafický výstup?
Samozřejmě existují bindingy na všechny možné GUI knihovny.
• gtk, Qt, wxWidgets• SDL, OpenGL
Haskellově specifické věci jsou zajímavější:
• Back-end: JuicyPixels (&repa)• Generativní grafika: Rasterific• Specifická generativní grafika: Chart• Interaktivní generativní grafika: Gloss & NotGloss
296
![Page 439: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/439.jpg)
JuicyPixels
import Codec.PicturereadImage :: FilePath→ IO (Either String DynamicImage)
DynamicImage je union pro všechny možné reprezentace pixelů, např.ImageRGBA8 (Image PixelRGBA8) neboImageYCbCr8 (Image PixelYCbCr8).
writeDynamicBitmap ::
FilePath→ DynamicImage→ IO (Either String Bool)writeBitmap :: BmpEncodable pixel⇒FilePath→ Image pixel→ IO ()
writePng :: PngSavable pixel⇒FilePath→ Image pixel→ IO ()
...297
![Page 440: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/440.jpg)
Co s obrázkem?
Vyrobit obrázek z funkce:
generateImage :: Pixel px ⇒(Int→ Int→ px)→ Int→ Int→ Image px
map-like zjednodušení:
pixelMap :: Pixel a, Pixel b⇒(a→ b)→ Image a→ Image b
298
![Page 441: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/441.jpg)
Pixely
Pixely je možné manipulovat přímo jako číselné hodnoty.
data PixelRGB8 = PixelRGB8 ! Pixel8 ! Pixel8 ! Pixel8type PixelF = Floatdata PixelCMYK16 = PixelCMYK16 ! Pixel16 ! Pixel16
! Pixel16 ! Pixel16
299
![Page 442: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/442.jpg)
Strict&Unboxed
Vykřičník v datovém typu znamená, že data nejsou ‘boxed’. (Tj. nemůžou býtméně definovaná než celá struktura.)
Praktický význam:
data A = A Int Int
A
Int Int
data A = A ! Int
A Int Int
Pointery navíc jsou klíčový rozdíl pro rychlost výpočtů na velkém množstvímalých dat.
300
![Page 443: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/443.jpg)
Strict&Unboxed (odbočka)
Jak tomu pomoct?
seq :: a→ b→ b
“The value of seq a b is bottom if a is bottom, and otherwise equal to b. Inother words, it evaluates the first argument a to weak head normal form(WHNF). seq is usually introduced to improve performance by avoidingunneeded laziness.”
f ! a = ...
f $! a
{-# INLINE f #-}
301
![Page 444: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/444.jpg)
Strict&Unboxed (prakticky)
Psát všude vykřičníky je otrava. Většina používaných kontejnerů má striktnívarianty:
• Data.Vector.Unboxed,Data.Vector.Primitive• Data.Set.Strict,Data.Map.Strict, . . .• Control.Monad.Trans:
• State.Strict,Writer.Strict, . . .• RWS.Strict
• strict :: Strict lazy strict⇒ Iso′ lazy strict• unpackStrict :: ByteString→ [Word8]
• foldl′
302
![Page 445: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/445.jpg)
Repa
‘Regular parallel arrays’ (polymorfní vícedimenzionální primitivní striktníarraye)
• regularita→ rychlost• fůzování arrayových funkcí→ víc rychlosti• lowlevelové optimalizace při překladu s LLVM→ ještě víc rychlosti• paralelní vyhodnocování skoro zadarmo
303
![Page 446: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/446.jpg)
Repa
type DIM0 = Ztype DIM1 = DIM0 : . Inttype DIM2 = DIM1 : . Int...
• R.Array U DIM2 Float — matice• R.Array V Z Int — 1 bod• (Z : . 1 : . 2 : . 3) — index ve 3D arrayi• (Z : . 3) — index v 1D arrayi
304
![Page 447: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/447.jpg)
Repa
map :: (Shape sh, Source r a)⇒(a→ b)→ Array r sh a→ Array D sh b
zipWith :: (Shape sh, Source r1 a, Source r2 b)⇒(a→ b→ c)→ Array r1 sh a→ Array r2 sh b→ Array D sh c
fromFunction ::
sh→ (sh→ a)→ Array D sh a
Výpočet:
computeUnboxedS :: (Load r1 sh e,Unbox e)⇒Array r1 sh e→ Array U sh e
computeUnboxedP :: (Load r1 sh e,Monad m,Unbox e)⇒Array r1 sh e→ m (Array U sh e)
305
![Page 448: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/448.jpg)
Repa
map :: (Shape sh, Source r a)⇒(a→ b)→ Array r sh a→ Array D sh b
zipWith :: (Shape sh, Source r1 a, Source r2 b)⇒(a→ b→ c)→ Array r1 sh a→ Array r2 sh b→ Array D sh c
fromFunction ::
sh→ (sh→ a)→ Array D sh a
Výpočet:
computeUnboxedS :: (Load r1 sh e,Unbox e)⇒Array r1 sh e→ Array U sh e
computeUnboxedP :: (Load r1 sh e,Monad m,Unbox e)⇒Array r1 sh e→ m (Array U sh e)
305
![Page 449: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/449.jpg)
Repa (použití)
ghc -O -fllvm -threaded -rtsopts program.hs
./program +RTS -N 16
306
![Page 450: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/450.jpg)
Příklad (zpět k JuicyPixels)
import Data.Compleximport Data.Wordimport Codec.Picturejulia limit z a0 = run a0 0where run c i| i > limit = limit| magnitude c> 2 = i| otherwise = run (c ∗ c + z) (i + 1)
juliapix x y = (fromIntegral :: Int→ Word8) $
julia 255 (0.141:+0.6) $
((−1.25):+(−1.25))
+ 0.0025 ∗ (fromIntegral x:+fromIntegral y)
main = writePng "fractal.png" $
generateImage juliapix 1000 1000 307
![Page 451: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/451.jpg)
307
![Page 452: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/452.jpg)
Jak nakreslit něco složitějšího?
import Codec.Picture (PixelRGBA8 (. .),writePng)
import Graphics.Rasterificwhite = PixelRGBA8 255 255 255 255drawColor = PixelRGBA8 0 0 x86 0 xc1 255
main = writePng "kulaty.png" $
renderDrawing 200 200 white $
fill $ circle (V2 100 100) 75
Další knihovny: diagrams (vektorové diagramy, zarovnávání, šipky, ...),juicypixels-repa (brutálnější výpočty), friday (běžné rastrovévýpočty typu blur)
308
![Page 453: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/453.jpg)
308
![Page 454: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/454.jpg)
Grafy
Generovat pěkné grafy je tradičně těžké.
State-of-art: ggplot2
GGplot:plot(data) + geom\_point(pretest,posttest) + geom\_quantile() + title(...)
Haskell: Jednotlivé kusy grafu jsou substruktury, můžeme do nich vrtatpomocí čoček.
309
![Page 455: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/455.jpg)
Chartimport Graphics.Rendering.Chartimport Data.Colourimport Data.Colour.Namesimport Data.Default.Classimport Graphics.Rendering.Chart · Backend.Cairoimport Control.Lens
setLinesBlue :: PlotLines a b→ PlotLines a bsetLinesBlue = plot_lines_style · line_color .˜ opaque blue
chart = toRenderable layoutwheream :: Double→ Doubleam x = (sin (x ∗ 3.14159 / 45) + 1) / 2 ∗ (sin (x ∗ 3.14159 / 5))
sinusoid1 = plot_lines_values .˜ [[(x, (am x)) | x← [0, (0.5) . . 400]]]$ plot_lines_style · line_color .˜ opaque blue$ plot_lines_title .˜ "am" $ def
sinusoid2 = plot_points_style .˜ filledCircles 2 (opaque red)$ plot_points_values .˜ [(x, (am x)) | x ← [0, 7 . . 400 ] ]$ plot_points_title .˜ "am points" $ def
layout = layout_title .˜ "Amplitude Modulation"$ layout_plots .˜ [ toPlot sinusoid1, toPlot sinusoid2 ] $ def
main = renderableToFile def "example1_big.png" chart 310
![Page 456: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/456.jpg)
Chart
311
![Page 457: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/457.jpg)
Chart (Monads!)
import Graphics.Rendering.Chart.Easyimport Graphics.Rendering.Chart · Backend.Cairosignal :: [Double]→ [(Double,Double)]
signal xs = [(x, (sin (x ∗ 3.14159 / 45) + 1)
/ 2 ∗ (sin (x ∗ 3.14159 / 5)))
| x← xs]
main = toFile def "example1_big.png" $ dolayout_title . = "Amplitude Modulation"setColors [opaque blue, opaque red ]
plot (line "am" [signal [0, (0.5) . . 400]])
plot (points "am points" (signal [0, 7 . . 400]))
312
![Page 458: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/458.jpg)
Gloss
“Get something cool on the screen in under 10 minutes.”
312
![Page 459: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/459.jpg)
Gloss
Gloss poskytuje jednoduchý datový typ na popis scény a poměrně efektivnízobrazování scény pomocí OpenGL.
Scéna:
type Point = (Float, Float)type Path = [Point ]data Picture =
| Blank| Polygon Path | Line Path | Circle Float| Text String| Color Color Picture| Translate Float Float Picture| Rotate Float Picture | Scale Float Picture| ...
313
![Page 460: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/460.jpg)
Gloss
Je to rychlé?
Je to lazy.
313
![Page 461: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/461.jpg)
Gloss
Je to rychlé?
Je to lazy.
313
![Page 462: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/462.jpg)
Gloss
import Graphics.Glossdisplay :: Display → Color → Picture→ IO ()
main = display (InWindow "Okno!" (200, 200) (10, 10))
white (ThickCircle 50 3)
animate :: Display → Color → (Float→ Picture)→ IO ()
main = animate FullScreenwhite $ λt→ Pictures $ flip map [1 . . 4] $ λx→Rotate (90 ∗ x + 20 ∗ t) $
Translate 80 0 $
ThickCircle 20 (3 + 2 ∗ sin t)
314
![Page 463: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/463.jpg)
Gloss
simulate :: Display→ Color→ Int -- fps→ model -- cokoliv→ (model→ Picture)
→ (ViewPort→ Float→ model→ model)→ IO ()
315
![Page 464: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/464.jpg)
Gloss
play :: Display→ Color→ Int -- fps→ world -- popis světa→ (world→ Picture) -- render→ (Event→ world→ world)
→ (Float→ world→ world)
→ IO ()
316
![Page 465: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/465.jpg)
3D: not-gloss
data VisObject a = VisObjects [VisObject a]| Trans (V3 a) (VisObject a)| RotQuat (Quaternion a) (VisObject a)| RotEulerDeg (Euler a) (VisObject a)| Scale (a, a, a) (VisObject a)| Cylinder (a, a) GlossColor.Color| Box (a, a, a) Flavour GlossColor.Color| Ellipsoid (a, a, a) Flavour GlossColor.Color| Line (Maybe a) [V3 a] GlossColor.Color| Arrow (a, a) (V3 a) GlossColor.Color| Plane (V3 a) GlossColor.Color GlossColor.Color| Triangle (V3 a) (V3 a) (V3 a) GlossColor.Color| Quad (V3 a) (V3 a) (V3 a) (V3 a) GlossColor.Color| Text3d String (V3 a) BitmapFont GlossColor.Color| Text2d String (a, a) BitmapFont GlossColor.Color| Points [V3 a] (Maybe GLfloat) GlossColor.Color| ObjModel LoadedObjModel GlossColor.Color| ...
317
![Page 466: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/466.jpg)
3D: not-gloss
play :: Real b⇒Options→ Double -- sample time→ world -- initial state→ (world→ (VisObject b,Maybe Cursor)) -- draw function→ (Float→ world→ world) -- state propogation function→ (world→ IO ()) -- set where camera looks→ Maybe (world→ Key → KeyState→ Modifiers→ Position→ world)
→ Maybe (world→ Position→ world) -- mouse drag→ Maybe (world→ Position→ world) -- mouse move→ IO ()
318
![Page 467: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/467.jpg)
Debugování, testování, benchmarking
![Page 468: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/468.jpg)
Jak debugovat Haskell?
Problém: koukání debuggerem na proměnné a postup výpočtu nedávásmysl.
• To je ve skutečnosti dobře.• Proměnné neexistují a hodnoty většinou nemají hodnotu (jen thunk).• Postup výpočtu je pro člověka obtížně stravitelný• Skompilovaný kód nemá s původním nutně společnou strukturu
Místo toho:
• Máme efektivní interpreter• Máme užitečný typový systém• Umíme trasovat
319
![Page 469: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/469.jpg)
Jak debugovat Haskell?
Problém: koukání debuggerem na proměnné a postup výpočtu nedávásmysl.
• To je ve skutečnosti dobře.• Proměnné neexistují a hodnoty většinou nemají hodnotu (jen thunk).• Postup výpočtu je pro člověka obtížně stravitelný• Skompilovaný kód nemá s původním nutně společnou strukturu
Místo toho:
• Máme efektivní interpreter• Máme užitečný typový systém• Umíme trasovat
319
![Page 470: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/470.jpg)
Program nejde skompilovat kvůli typům
Běžný programátor nemá v hlavě typový systém. (Matfyzáci by ale měli.)
Nejlepší řešení: _ a.k.a. Typed Hole
(+1) [1, 2, 3]
Found hole: :: (Integer → Integer)→ [ Integer ]→ t
foldl 0 ["asd", "qwe"]
Found hole: :: b→ [Char ]→ bWhere: b is a rigid type variable with inferred typeNum b⇒ b
Užitečná pomůcka: Hoogle umi type search.
320
![Page 471: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/471.jpg)
Program nejde skompilovat kvůli typům
Běžný programátor nemá v hlavě typový systém. (Matfyzáci by ale měli.)
Nejlepší řešení: _ a.k.a. Typed Hole
(+1) [1, 2, 3]
Found hole: :: (Integer → Integer)→ [ Integer ]→ t
foldl 0 ["asd", "qwe"]
Found hole:
:: b→ [Char ]→ bWhere: b is a rigid type variable with inferred typeNum b⇒ b
Užitečná pomůcka: Hoogle umi type search.
320
![Page 472: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/472.jpg)
Program nejde skompilovat kvůli typům
Běžný programátor nemá v hlavě typový systém. (Matfyzáci by ale měli.)
Nejlepší řešení: _ a.k.a. Typed Hole
(+1) [1, 2, 3]
Found hole: :: (Integer → Integer)→ [ Integer ]→ t
foldl 0 ["asd", "qwe"]
Found hole: :: b→ [Char ]→ bWhere: b is a rigid type variable with inferred typeNum b⇒ b
Užitečná pomůcka: Hoogle umi type search.
320
![Page 473: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/473.jpg)
Typová chyba je moc složitá
Běžný problém: Chyba se propaguje do jiné funkce a problém způsobí ažtam.
let concatMonoids = foldr mempty (�)...
print $ concatMonoids ["neco", "tamto"]
No instance for (Show (m0→ m0→ m0)) ?
321
![Page 474: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/474.jpg)
Typová chyba je moc složitá
Běžný problém: Chyba se propaguje do jiné funkce a problém způsobí ažtam.
let concatMonoids = foldr mempty (�)...
print $ concatMonoids ["neco", "tamto"]
No instance for (Show (m0→ m0→ m0)) ?
321
![Page 475: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/475.jpg)
Typová chyba je moc složitá
let concatMonoids = foldr mempty (�)...
print $ (concatMonoids ["a", "bcd"] :: )
Found type wildcard standing form0→ m0→ m0
322
![Page 476: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/476.jpg)
Typová chyba je moc složitá
let concatMonoids ::
concatMonoids = foldr mempty (�)...
print $ concatMonoids ["a", "bcd"]
Found type wildcard standing for [a]→ m0→ m0→ m0
...to úplně nesedí s očekáváním!
323
![Page 477: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/477.jpg)
Typová chyba je moc složitá
let concatMonoids :: Monoid m⇒ [m]→ mconcatMonoids = foldr mempty (�)
...
print $ concatMonoids ["a", "bcd"]
Couldn’t match typem withm0→ m0→ m0In the expression: foldr mempty (�)
Chybová hláška nejde hlouběji, problém bude ve foldr
:t foldr
foldr :: Foldable t⇒ (a→ b→ b)→ b→ t a→ b
324
![Page 478: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/478.jpg)
Typová chyba je moc složitá
Po opravách se můžeme podívat, jestli si typový systém nemyslí něcogeneričtějšího:
:t foldr (<>) mempty
foldr (�) mempty :: (Monoid b, Foldable t)⇒ t b→ b
325
![Page 479: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/479.jpg)
Trace
Co když potřebujeme rychle vidět, co si program myslí uprostřed nějakéhovýpočtu?
• C-style řešení: printf• Haskell, SW development řešení:
Všechny funkce předělám na IO, aby fungoval print!• Haskell, vhodné dočasné neinvazivní řešení: Debug.Trace
trace :: String→ a→ a
ghci> if 3 < 4 then trace "funguje" 5 else 6funguje5
(Vedlejší efekty a strictness můžou rozbít zbytek programu, v produkčnímkódu nemají co dělat.)
326
![Page 480: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/480.jpg)
Trace
Co když potřebujeme rychle vidět, co si program myslí uprostřed nějakéhovýpočtu?
• C-style řešení: printf• Haskell, SW development řešení:
Všechny funkce předělám na IO, aby fungoval print!• Haskell, vhodné dočasné neinvazivní řešení: Debug.Trace
trace :: String→ a→ a
ghci> if 3 < 4 then trace "funguje" 5 else 6funguje5
(Vedlejší efekty a strictness můžou rozbít zbytek programu, v produkčnímkódu nemají co dělat.)
326
![Page 481: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/481.jpg)
Trace
trace :: String→ val→ valtraceShow :: Show msg⇒→ msg→ val→ valtraceShowId :: Show val⇒ val→ valtraceM :: Applicative f ⇒ String→ f ()
traceShowM :: (Show msg,Applicative f)⇒ msg→ f ()
327
![Page 482: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/482.jpg)
Magie: SimpleReflect
import Debug.SimpleReflectproduct [1 . . 10] :: Expr
; 1 ∗ 1 ∗ 2 ∗ 3 ∗ 4 ∗ 5 ∗ 6 ∗ 7 ∗ 8 ∗ 9 ∗ 10
foldr (+) 0 [1 . . 4] :: Expr; 1 + (2 + (3 + (4 + 0)))
map f [1, 2, 3] :: [Expr ]; [f 1, f 2, f 3]
scanl f 0 [1 . . 3] :: [Expr ]; [0, f 0 1, f (f 0 1) 2, f (f (f 0 1) 2) 3]
mapM_ print $ reduction (1 ∗ 2 + 3 ∗ 4)
; 1 ∗ 2 + 3 ∗ 42 + 3 ∗ 42 + 1214 328
![Page 483: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/483.jpg)
Unit testy
Unit testy nejsou v Haskellu populární, většinou jde o (zlo)zvyk z jinýchjazyku.
/ test-driven development je nahrazený type-driven developmentem/ absence vedlejších efektů dovoluje i obrovské programy testovat v
ghci
/ unit testy nejsou integrační testy/ fungující polymorfismus zmenšuje pokrytelný prostor☼ správně napsané unit testy jdou považovat za vyšší variantu
dokumentace☼ v týmovém prostředí je unit testing univerzální ochranou proti ostatním
programátorům
329
![Page 484: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/484.jpg)
Unit testy
Unit testy nejsou v Haskellu populární, většinou jde o (zlo)zvyk z jinýchjazyku.
/ test-driven development je nahrazený type-driven developmentem/ absence vedlejších efektů dovoluje i obrovské programy testovat v
ghci
/ unit testy nejsou integrační testy/ fungující polymorfismus zmenšuje pokrytelný prostor☼ správně napsané unit testy jdou považovat za vyšší variantu
dokumentace☼ v týmovém prostředí je unit testing univerzální ochranou proti ostatním
programátorům
329
![Page 485: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/485.jpg)
Unit testy
Unit testy nejsou v Haskellu populární, většinou jde o (zlo)zvyk z jinýchjazyku.
/ test-driven development je nahrazený type-driven developmentem/ absence vedlejších efektů dovoluje i obrovské programy testovat v
ghci
/ unit testy nejsou integrační testy/ fungující polymorfismus zmenšuje pokrytelný prostor☼ správně napsané unit testy jdou považovat za vyšší variantu
dokumentace☼ v týmovém prostředí je unit testing univerzální ochranou proti ostatním
programátorům
329
![Page 486: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/486.jpg)
Unit testy
Unit testy nejsou v Haskellu populární, většinou jde o (zlo)zvyk z jinýchjazyku.
/ test-driven development je nahrazený type-driven developmentem/ absence vedlejších efektů dovoluje i obrovské programy testovat v
ghci
/ unit testy nejsou integrační testy/ fungující polymorfismus zmenšuje pokrytelný prostor☼ správně napsané unit testy jdou považovat za vyšší variantu
dokumentace☼ v týmovém prostředí je unit testing univerzální ochranou proti ostatním
programátorům
329
![Page 487: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/487.jpg)
Unit testy
Unit testy nejsou v Haskellu populární, většinou jde o (zlo)zvyk z jinýchjazyku.
/ test-driven development je nahrazený type-driven developmentem/ absence vedlejších efektů dovoluje i obrovské programy testovat v
ghci
/ unit testy nejsou integrační testy/ fungující polymorfismus zmenšuje pokrytelný prostor☼ správně napsané unit testy jdou považovat za vyšší variantu
dokumentace☼ v týmovém prostředí je unit testing univerzální ochranou proti ostatním
programátorům
329
![Page 488: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/488.jpg)
Unit testy
Unit testy nejsou v Haskellu populární, většinou jde o (zlo)zvyk z jinýchjazyku.
/ test-driven development je nahrazený type-driven developmentem/ absence vedlejších efektů dovoluje i obrovské programy testovat v
ghci
/ unit testy nejsou integrační testy/ fungující polymorfismus zmenšuje pokrytelný prostor☼ správně napsané unit testy jdou považovat za vyšší variantu
dokumentace☼ v týmovém prostředí je unit testing univerzální ochranou proti ostatním
programátorům
329
![Page 489: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/489.jpg)
HUnit
Běžné použití:
• cabal nastavíme na používání unit testů• do test/ vyrobíme samostatný program který spouští testování• Použujeme Test.HUnit k vyrobení pěkného interface programu
330
![Page 490: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/490.jpg)
HUnit
test/main.hs
import FindIdentifier (findIdentifier)import Test.HUnittestEmpty = TestCase $ assertEqual"Should get Nothing from an empty string"Nothing (findIdentifier "" (1, 1))
testNegCursor = TestCase $ assertEqual"Should get Nothing when cursor is negative"Nothing (findIdentifier "a" (−1,−1))
testMinimal = TestCase $ assertEqual"Minimal program"(Just "main") (findIdentifier "main = print 42" (1, 2))
main = runTestTT $ TestList[testEmpty, testNegCursor, testMinimal]
331
![Page 491: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/491.jpg)
QuickCheck
Psát testy ručně je otrava. Použijme fuzzer.
import Test.QuickCheckprop_reverse :: [ Int ]→ Boolprop_reverse xs = reverse (reverse xs) ≡ xs
ghci> quickCheck prop_reverse>>> quickCheck prop_reverse+++ OK, passed 100 tests.
332
![Page 492: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/492.jpg)
QuickCheck
ghci> quickCheck $ \a -> a + 1 == a + 1+++ OK, passed 100 tests.ghci> quickCheck $ \a -> abs (a*a) == a*a+++ OK, passed 100 tests.
ghci> quickCheck $ \a -> abs (a*a*a) == a*a*a*** Failed! Falsifiable (after 4 tests and 2 shrinks):-1
333
![Page 493: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/493.jpg)
QuickCheck
ghci> quickCheck $\a -> (if a == 20 then 666 else a) == a
+++ OK, passed 100 tests.
ghci> quickCheck . withMaxSuccess 10000 $\a -> (if a == 20 then 666 else a) == a
*** Failed! Falsifiable (after 22 tests):20
334
![Page 494: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/494.jpg)
QuickCheck
ghci> quickCheck $ \xs n -> xs !! n == head (drop n xs)*** Failed! Exception: ’Prelude.!!: index too large’[]0
ghci> quickCheck $ \(NonEmpty xs) (NonNegative n) ->xs !! n == head (drop n xs)
*** Failed! Exception: ’Prelude.!!: index too large’NonEmpty {getNonEmpty = [()]}NonNegative {getNonNegative = 1}
335
![Page 495: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/495.jpg)
QuickCheck
ghci> quickCheck $ \(NonEmpty xs) (NonNegative n) ->n < length xs ==> xs !! n == head (drop n xs)
+++ OK, passed 100 tests; 61 discarded.
Jak QuickCheck hledá, co testovat?
336
![Page 496: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/496.jpg)
Jak QuickCheck hledá, co testovat?
class Arbitrary a wherearbitrary :: Gen ashrink :: a→ [a]
• Gen je State-like monáda poskytující náhodná čísla• arbitrary by mělo v Gen výpočtu vyrobit náhodný objekt typu a• shrink by mělo z většího generovaného náhodného objektu vyrobit
pod-objekty (např. kvůli přesnější lokalizaci chyby)
337
![Page 497: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/497.jpg)
Benchmarking
Benchmarky typicky vyžadují:
• spustit víc běhů• změřit výsledek na různých velikostech dat• neměřit okamžité líné vyhodnocování
Haskellí řešení: Criterion +DeepSeq
338
![Page 498: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/498.jpg)
Criterion — demo
Zjistíme, o kolik je Integer pomalejší než Int.
sumN n = sum [1 . . n]
fact n = product [1 . . n]
sumNi = sumN :: Int→ IntsumNhi = sumN :: Integer → Integerfacti = fact :: Int→ Intfacthi = fact :: Integer → Integer
problemSizes = [1, 30 . . 100]
mkBench f size = bench (show size) $ nf f $ fromInteger sizemkBenches f = map (mkBench f) problemSizes
339
![Page 499: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/499.jpg)
Criterion — demo
Zjistíme, o kolik je Integer pomalejší než Int.
sumN n = sum [1 . . n]
fact n = product [1 . . n]
sumNi = sumN :: Int→ IntsumNhi = sumN :: Integer → Integerfacti = fact :: Int→ Intfacthi = fact :: Integer → Integer
problemSizes = [1, 30 . . 100]
mkBench f size = bench (show size) $ nf f $ fromInteger sizemkBenches f = map (mkBench f) problemSizes
339
![Page 500: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/500.jpg)
Criterion — demo
Zjistíme, o kolik je Integer pomalejší než Int.
sumN n = sum [1 . . n]
fact n = product [1 . . n]
sumNi = sumN :: Int→ IntsumNhi = sumN :: Integer → Integerfacti = fact :: Int→ Intfacthi = fact :: Integer → Integer
problemSizes = [1, 30 . . 100]
mkBench f size = bench (show size) $ nf f $ fromInteger sizemkBenches f = map (mkBench f) problemSizes
339
![Page 501: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/501.jpg)
Criterion — demo
Zjistíme, o kolik je Integer pomalejší než Int.
sumN n = sum [1 . . n]
fact n = product [1 . . n]
sumNi = sumN :: Int→ IntsumNhi = sumN :: Integer → Integerfacti = fact :: Int→ Intfacthi = fact :: Integer → Integer
problemSizes = [1, 30 . . 100]
mkBench f size = bench (show size) $ nf f $ fromInteger sizemkBenches f = map (mkBench f) problemSizes
339
![Page 502: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/502.jpg)
Criterion — demo
main = defaultMain [
bgroup "sum-int" $ mkBenches sumNi,bgroup "sum-integer" $ mkBenches sumNhi,bgroup "fact-int" $ mkBenches facti,bgroup "fact-integer" $ mkBenches facthi ]
Hint: je vhodné kompilovat s -O
340
![Page 503: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/503.jpg)
Criterion — demo
main = defaultMain [
bgroup "sum-int" $ mkBenches sumNi,bgroup "sum-integer" $ mkBenches sumNhi,bgroup "fact-int" $ mkBenches facti,bgroup "fact-integer" $ mkBenches facthi ]
Hint: je vhodné kompilovat s -O
340
![Page 504: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/504.jpg)
Criterion — demo
$ ./ints --helpMicrobenchmark suite - built with criterion 1.5.2.0
Usage: ints [-I|--ci CI] [-L|--time-limit SECS][--resamples COUNT] ...
$ ./intsbenchmarking sum-int/1time 8.832 ns (8.723 ns .. 8.952 ns)
0.996 R2 (0.991 R2 .. 0.999 R2)mean 9.068 ns (8.829 ns .. 9.675 ns)std dev 1.246 ns (536.7 ps .. 2.682 ns)variance introduced by outliers: 96% (severely inflated)...
341
![Page 505: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/505.jpg)
Criterion — výsledek
benchmarking sum-int/88time 75.10 ns (74.46 ns .. 76.07 ns)
benchmarking sum-integer/88time 1.529 us (1.516 us .. 1.550 us)
benchmarking fact-int/88time 103.7 ns (99.13 ns .. 108.3 ns)
benchmarking fact-integer/88time 3.645 us (3.593 us .. 3.723 us)
342
![Page 506: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/506.jpg)
Criterion — výsledek
$ ./ints --output vysledek.html
343
![Page 507: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/507.jpg)
Criterion — výsledek
$ ./ints --output vysledek.html
344
![Page 508: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/508.jpg)
nf na vlastním typu
Problém: není genericky jasné, jak (a jak moc) forcovat složitější typy.
nf :: Control.DeepSeq.NFData b⇒(a→ b)→ a→ Benchmarkable
data Tree = Leaf Int | Branch Tree Treeinstance NFData Tree wherernf (Leaf i) = rnf i ‘seq‘ ()
rnf (Branch l r) = rnf l ‘seq‘ rnf r ‘seq‘ ()
Definice seq nesouvisí s pořadím vyhodnocení!
Pokud amá slabou hlavově normální formu (WHNF), seq a b vrátí b. Pokuda nemá WHNF, seq a b taky nemá WHNF.
(intuice: min a b)
345
![Page 509: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/509.jpg)
nf na vlastním typu
Problém: není genericky jasné, jak (a jak moc) forcovat složitější typy.
nf :: Control.DeepSeq.NFData b⇒(a→ b)→ a→ Benchmarkable
data Tree = Leaf Int | Branch Tree Treeinstance NFData Tree wherernf (Leaf i) = rnf i ‘seq‘ ()
rnf (Branch l r) = rnf l ‘seq‘ rnf r ‘seq‘ ()
Definice seq nesouvisí s pořadím vyhodnocení!
Pokud amá slabou hlavově normální formu (WHNF), seq a b vrátí b. Pokuda nemá WHNF, seq a b taky nemá WHNF.
(intuice: min a b)
345
![Page 510: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/510.jpg)
Webové aplikace
![Page 511: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/511.jpg)
Architektura typické webové aplikace
• Databáze• CokolivSQL ElasticSearch, Mongo, Redis, . . .
• API klient• Back-end
• webserver, request routing, API endpointy• API
• HTML• JSON• . . .
• Front-end• Javascript
• Browser
Haskell jde nasadit na všech úrovních.
346
![Page 512: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/512.jpg)
Architektura typické webové aplikace
• Databáze• CokolivSQL ElasticSearch, Mongo, Redis, . . .
• API klient• Back-end
• webserver, request routing, API endpointy• API
• HTML• JSON• . . .
• Front-end• Javascript
• Browser
Haskell jde nasadit na všech úrovních.
346
![Page 513: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/513.jpg)
HTTP klient
import Network.HTTP.Simpleimport qualified Data.ByteString.Lazy.Char8 as L8main = doresponse← httpLBS "https://test.cz/stranka"
print (getResponseStatusCode response)
L8.putStrLn $ getResponseBody response
347
![Page 514: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/514.jpg)
HTTP klient
import Network.HTTP.Simpleimport qualified Data.ByteString.Lazy.Char8 as L8main = doresponse← httpLBS "https://test.cz/stranka"
print (getResponseStatusCode response)
L8.putStrLn $ getResponseBody response
347
![Page 515: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/515.jpg)
HTTP klient
import Network.HTTP.Simpleimport qualified Data.ByteString.Lazy.Char8 as L8main = doresponse← httpLBS "https://test.cz/stranka"
print (getResponseStatusCode response)
L8.putStrLn $ getResponseBody response
347
![Page 516: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/516.jpg)
HTTP klient
import Network.HTTP.Simpleimport qualified Data.ByteString.Lazy.Char8 as L8main = doresponse← httpLBS "https://test.cz/stranka"
print (getResponseStatusCode response)
L8.putStrLn $ getResponseBody response
347
![Page 517: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/517.jpg)
API klient
import Data.Aeson (Value)import qualified Data.ByteString.Char8 as S8import qualified Data.Yaml as Yamlimport Network.HTTP.Simplemain :: IO ()
main = dorequest′ ← parseRequest "POST http://data.cz/vec"let request
= setRequestMethod "PUT"$ setRequestPath "/polozit"$ setRequestQueryString [("parametr", Just "hodnota")]$ setRequestBodyLBS "DataData"$ setRequestSecure True$ setRequestPort 443$ request′
response← httpJSON request
print $ getResponseHeader "Content-Type" responseS8.putStrLn $ Yaml.encode (getResponseBody response :: Value)
348
![Page 518: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/518.jpg)
API klient
import Data.Aeson (Value)import qualified Data.ByteString.Char8 as S8import qualified Data.Yaml as Yamlimport Network.HTTP.Simplemain :: IO ()
main = dorequest′ ← parseRequest "POST http://data.cz/vec"let request
= setRequestMethod "PUT"$ setRequestPath "/polozit"$ setRequestQueryString [("parametr", Just "hodnota")]$ setRequestBodyLBS "DataData"$ setRequestSecure True$ setRequestPort 443$ request′
response← httpJSON request
print $ getResponseHeader "Content-Type" responseS8.putStrLn $ Yaml.encode (getResponseBody response :: Value)
348
![Page 519: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/519.jpg)
API klient
import Data.Aeson (Value)import qualified Data.ByteString.Char8 as S8import qualified Data.Yaml as Yamlimport Network.HTTP.Simplemain :: IO ()
main = dorequest′ ← parseRequest "POST http://data.cz/vec"let request
= setRequestMethod "PUT"$ setRequestPath "/polozit"$ setRequestQueryString [("parametr", Just "hodnota")]$ setRequestBodyLBS "DataData"$ setRequestSecure True$ setRequestPort 443$ request′
response← httpJSON request
print $ getResponseHeader "Content-Type" responseS8.putStrLn $ Yaml.encode (getResponseBody response :: Value)
348
![Page 520: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/520.jpg)
API klient
import Data.Aeson (Value)import qualified Data.ByteString.Char8 as S8import qualified Data.Yaml as Yamlimport Network.HTTP.Simplemain :: IO ()
main = dorequest′ ← parseRequest "POST http://data.cz/vec"let request
= setRequestMethod "PUT"$ setRequestPath "/polozit"$ setRequestQueryString [("parametr", Just "hodnota")]$ setRequestBodyLBS "DataData"$ setRequestSecure True$ setRequestPort 443$ request′
response← httpJSON request
print $ getResponseHeader "Content-Type" responseS8.putStrLn $ Yaml.encode (getResponseBody response :: Value)
348
![Page 521: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/521.jpg)
JSON
Standardní řešení parsování a generování JSONu jeData.Aeson.
data Value = Object (Map Text Value)
| Array (Vector Value)
| String Text | Number Number | Bool Bool| Null
class FromJSON a whereparseJSON :: Value→ Parser a
class ToJSON a wheretoJSON :: a→ Value
349
![Page 522: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/522.jpg)
JSON
data Hodnota = Hodnota {mnozstvi :: Double,jednotka :: String}
instance ToJSON Hodnota wheretoJSON (Hodnota m j) = Object $
fromList [("mnozstvi",Number (D m)),
("jednotka", String j)]
instance FromJSON Hodnota whereparseJSON (Object a) =
Hodnota 〈$〉 a . : "mnozstvi"〈∗〉 a . : "jednotka"
parseJSON = mzero
350
![Page 523: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/523.jpg)
JSON
data Hodnota = Hodnota {mnozstvi :: Double,jednotka :: String}
instance ToJSON Hodnota wheretoJSON (Hodnota m j) = Object $
fromList [("mnozstvi",Number (D m)),
("jednotka", String j)]
instance FromJSON Hodnota whereparseJSON (Object a) =
Hodnota 〈$〉 a . : "mnozstvi"〈∗〉 a . : "jednotka"
parseJSON = mzero
350
![Page 524: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/524.jpg)
JSON
data Hodnota = Hodnota {mnozstvi :: Double,jednotka :: String}
instance ToJSON Hodnota wheretoJSON (Hodnota m j) = Object $
fromList [("mnozstvi",Number (D m)),
("jednotka", String j)]
instance FromJSON Hodnota whereparseJSON (Object a) =
Hodnota 〈$〉 a . : "mnozstvi"〈∗〉 a . : "jednotka"
parseJSON = mzero
350
![Page 525: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/525.jpg)
JSON
data Hodnota = Hodnota {mnozstvi :: Double,jednotka :: String}
instance ToJSON Hodnota wheretoJSON (Hodnota m j) = Object $
fromList [("mnozstvi",Number (D m)),
("jednotka", String j)]
instance FromJSON Hodnota whereparseJSON (Object a) =
Hodnota 〈$〉 a . : "mnozstvi"〈∗〉 a . : "jednotka"
parseJSON = mzero
350
![Page 526: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/526.jpg)
Aeson
Výhoda: prakticky všechny JSONovité balíky umí transparentně používatinstance FromJSON a ToJSON; běžné typy mají instance předpřipravené.
Manuální použití:
encode :: ToJSON a ⇒ a→ ByteStringdecode :: FromJSON a⇒ ByteString→ Maybe a
decode "[123,234]" :: Maybe [ Int ]; Just [123, 234]
encode [123, 234]
; "[123,234]"
351
![Page 527: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/527.jpg)
HTML
Generovat HTML Haskellem ručně je poměrně jednoduché. Dostupnéknihovny minimalizují overhead slepování různých druhů stringů.
{-# LANGUAGE OverloadedStrings #-}import Text.Blaze.Html5 as Himport Text.Blaze.Html5.Attributes as A
Většina kombinátorů akceptuje ‘obsah’, monády jsou použité jako builder.
numbers n = docTypeHtml $ doH.head $ H.title "Natural numbers"body $ dop "A list of natural numbers:"ul $ forM_ [1 . . n] (li · toHtml)
352
![Page 528: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/528.jpg)
HTML
Generovat HTML Haskellem ručně je poměrně jednoduché. Dostupnéknihovny minimalizují overhead slepování různých druhů stringů.
{-# LANGUAGE OverloadedStrings #-}import Text.Blaze.Html5 as Himport Text.Blaze.Html5.Attributes as A
Většina kombinátorů akceptuje ‘obsah’, monády jsou použité jako builder.
numbers n = docTypeHtml $ doH.head $ H.title "Natural numbers"body $ dop "A list of natural numbers:"ul $ forM_ [1 . . n] (li · toHtml)
352
![Page 529: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/529.jpg)
HTML
Generovat HTML Haskellem ručně je poměrně jednoduché. Dostupnéknihovny minimalizují overhead slepování různých druhů stringů.
{-# LANGUAGE OverloadedStrings #-}import Text.Blaze.Html5 as Himport Text.Blaze.Html5.Attributes as A
Většina kombinátorů akceptuje ‘obsah’, monády jsou použité jako builder.
numbers n = docTypeHtml $ doH.head $ H.title "Natural numbers"body $ dop "A list of natural numbers:"ul $ forM_ [1 . . n] (li · toHtml)
352
![Page 530: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/530.jpg)
HTML
Generovat HTML Haskellem ručně je poměrně jednoduché. Dostupnéknihovny minimalizují overhead slepování různých druhů stringů.
{-# LANGUAGE OverloadedStrings #-}import Text.Blaze.Html5 as Himport Text.Blaze.Html5.Attributes as A
Většina kombinátorů akceptuje ‘obsah’, monády jsou použité jako builder.
numbers n = docTypeHtml $ doH.head $ H.title "Natural numbers"body $ dop "A list of natural numbers:"ul $ forM_ [1 . . n] (li · toHtml)
352
![Page 531: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/531.jpg)
HTML
Atributy:
image :: Htmlimage = img ! class_ "styled"
! src "lambda.png"! alt "An image of lambda."! A.id "theimage"
Obsah tagu:
odstavec :: Htmlodstavec = p ! class_ "zarovnat" $ em "Věta!"
alternativně:
odstavec = (p $ em "Věta!") ! class_ "zarovnat"
353
![Page 532: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/532.jpg)
HTML
Atributy:
image :: Htmlimage = img ! class_ "styled"
! src "lambda.png"! alt "An image of lambda."! A.id "theimage"
Obsah tagu:
odstavec :: Htmlodstavec = p ! class_ "zarovnat" $ em "Věta!"
alternativně:
odstavec = (p $ em "Věta!") ! class_ "zarovnat"
353
![Page 533: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/533.jpg)
SQLite overview
import Database.SQLite.SimpledbBracket :: (Connection→ IO a)→ IO adbBracket c = withConnection "database.sqlite"createUser user password =
dbBracket $ λdb→ dopwhash← newHash passwordexecutedb"INSERT INTO users (user, pwhash) VALUES (?,?)"(user :: String, pwhash :: String)
354
![Page 534: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/534.jpg)
SQLite overview
import Database.SQLite.SimpledbBracket :: (Connection→ IO a)→ IO adbBracket c = withConnection "database.sqlite"createUser user password =
dbBracket $ λdb→ dopwhash← newHash passwordexecutedb"INSERT INTO users (user, pwhash) VALUES (?,?)"(user :: String, pwhash :: String)
354
![Page 535: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/535.jpg)
SQLite overview
import Database.SQLite.SimpledbBracket :: (Connection→ IO a)→ IO adbBracket c = withConnection "database.sqlite"createUser user password =
dbBracket $ λdb→ dopwhash← newHash passwordexecutedb"INSERT INTO users (user, pwhash) VALUES (?,?)"(user :: String, pwhash :: String)
354
![Page 536: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/536.jpg)
SQLite overview
verifyPassword user password err f =
dbBracket $ λdb→withTransaction db $ dores←querydb"SELECT pwhash FROM users WHERE user = ?"(Only (user :: String)) :: IO [[String ]]
case res of[[hash]]→if checkHash password hashthen f dbelse err
→ err355
![Page 537: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/537.jpg)
SQLite overview
verifyPassword user password err f =
dbBracket $ λdb→withTransaction db $ dores←querydb"SELECT pwhash FROM users WHERE user = ?"(Only (user :: String)) :: IO [[String ]]
case res of[[hash]]→if checkHash password hashthen f dbelse err
→ err355
![Page 538: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/538.jpg)
SQLite overview
verifyPassword user password err f =
dbBracket $ λdb→withTransaction db $ dores←querydb"SELECT pwhash FROM users WHERE user = ?"(Only (user :: String)) :: IO [[String ]]
case res of[[hash]]→if checkHash password hashthen f dbelse err
→ err355
![Page 539: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/539.jpg)
SQLite overview
verifyPassword user password err f =
dbBracket $ λdb→withTransaction db $ dores←querydb"SELECT pwhash FROM users WHERE user = ?"(Only (user :: String)) :: IO [[String ]]
case res of[[hash]]→if checkHash password hashthen f dbelse err
→ err355
![Page 540: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/540.jpg)
Back-end
Nejběžnější balíky:
• wai — Web Application Interface, nízkoúrovňový základ pro HTTPprotokol
• warp — HTTP server• Yesod — warp obalený RESTful datovým modelem a Template
Haskellem• Scotty — podstatně tenčí a praktičtější obal• Servant — Typové definice API, automatické generování serverového,
klientského a javascriptového kódu.
356
![Page 541: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/541.jpg)
WAI
{-# LANGUAGE OverloadedStrings #-}import Network.Waiimport Network.HTTP.Typesimport Network.Wai.Handler.Warp (run)
app :: Applicationapp respond = doputStrLn "Někdo něco chce!"respond $ responseLBSstatus200[("Content-Type", "text/html")]
"<html><body><h1>Nazdar!</h1></body></html>"
main = run 8080 app
357
![Page 542: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/542.jpg)
WAI
{-# LANGUAGE OverloadedStrings #-}import Network.Waiimport Network.HTTP.Typesimport Network.Wai.Handler.Warp (run)
app :: Applicationapp respond = doputStrLn "Někdo něco chce!"respond $ responseLBSstatus200[("Content-Type", "text/html")]
"<html><body><h1>Nazdar!</h1></body></html>"
main = run 8080 app
357
![Page 543: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/543.jpg)
Scotty
{-# LANGUAGE OverloadedStrings #-}import Web.Scottyimport qualified Data.Text as Timport qualified Data.Map as Mmain = scotty 8080 $
get "/pozdrav/:jmeno" $ dojmeno← param "jmeno"html $ "<h1>Nazdar, " � jmeno � "!</h1>"
post "/log/:zprava" $ doparam "zprava">>= liftIO T.putStrLn · ("Log: "�)json $ M.fromList [("status" : "ok")]
358
![Page 544: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/544.jpg)
Scotty
{-# LANGUAGE OverloadedStrings #-}import Web.Scottyimport qualified Data.Text as Timport qualified Data.Map as Mmain = scotty 8080 $
get "/pozdrav/:jmeno" $ dojmeno← param "jmeno"html $ "<h1>Nazdar, " � jmeno � "!</h1>"
post "/log/:zprava" $ doparam "zprava">>= liftIO T.putStrLn · ("Log: "�)json $ M.fromList [("status" : "ok")]
358
![Page 545: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/545.jpg)
Scotty
{-# LANGUAGE OverloadedStrings #-}import Web.Scottyimport qualified Data.Text as Timport qualified Data.Map as Mmain = scotty 8080 $
get "/pozdrav/:jmeno" $ dojmeno← param "jmeno"html $ "<h1>Nazdar, " � jmeno � "!</h1>"
post "/log/:zprava" $ doparam "zprava">>= liftIO T.putStrLn · ("Log: "�)json $ M.fromList [("status" : "ok")]
358
![Page 546: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/546.jpg)
Scotty
{-# LANGUAGE OverloadedStrings #-}import Web.Scottyimport qualified Data.Text as Timport qualified Data.Map as Mmain = scotty 8080 $
get "/pozdrav/:jmeno" $ dojmeno← param "jmeno"html $ "<h1>Nazdar, " � jmeno � "!</h1>"
post "/log/:zprava" $ doparam "zprava">>= liftIO T.putStrLn · ("Log: "�)json $ M.fromList [("status" : "ok")]
358
![Page 547: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/547.jpg)
Scotty
{-# LANGUAGE OverloadedStrings #-}import Web.Scottyimport qualified Data.Text as Timport qualified Data.Map as Mmain = scotty 8080 $
get "/pozdrav/:jmeno" $ dojmeno← param "jmeno"html $ "<h1>Nazdar, " � jmeno � "!</h1>"
post "/log/:zprava" $ doparam "zprava">>= liftIO T.putStrLn · ("Log: "�)json $ M.fromList [("status" : "ok")]
358
![Page 548: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/548.jpg)
Servant{-# LANGUAGE DataKinds #-}{-# LANGUAGE DeriveGeneric #-}{-# LANGUAGE FlexibleInstances #-}{-# LANGUAGE GeneralizedNewtypeDeriving #-}{-# LANGUAGE MultiParamTypeClasses #-}{-# LANGUAGE OverloadedStrings #-}{-# LANGUAGE RankNTypes #-}{-# LANGUAGE ScopedTypeVariables #-}{-# LANGUAGE TypeOperators #-}
import Prelude ()
import Prelude.Compat
import Control.Monad.Exceptimport Control.Monad.Readerimport Data.Aesonimport Data.Aeson.Typesimport Data.Attoparsec.ByteStringimport Data.ByteString (ByteString)import Data.Listimport Data.Maybeimport Data.String.Conversionsimport Data.Time.Calendarimport GHC.Genericsimport Lucidimport Network.HTTP.Media ((//), (/ :))
import Network.Waiimport Network.Wai.Handler.Warpimport Servantimport System.Directoryimport Text.Blazeimport Text.Blaze.Html · Renderer.Utf8import Servant.Types.SourceT (source)import qualified Data.Aeson.Parserimport qualified Text.Blaze.Html
359
![Page 549: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/549.jpg)
Servant
type UserAPI =
"users" :〉 Get ‘[ JSON] [User ]: 〈|〉"posts" :〉 Get ‘[ JSON] [Post ]
server :: Server UserAPIserver = return users : 〈|〉 return postsuserAPI :: Proxy UserAPIuserAPI = Proxyapp :: Applicationapp = serve userAPI servermain = run 8080 app
360
![Page 550: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/550.jpg)
Servant
type UserAPI =
"users" :〉 Get ‘[ JSON] [User ]: 〈|〉"posts" :〉 Get ‘[ JSON] [Post ]
server :: Server UserAPIserver = return users : 〈|〉 return postsuserAPI :: Proxy UserAPIuserAPI = Proxyapp :: Applicationapp = serve userAPI servermain = run 8080 app
360
![Page 551: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/551.jpg)
Servant
type UserAPI =
"users" :〉 Get ‘[ JSON] [User ]: 〈|〉"posts" :〉 Get ‘[ JSON] [Post ]
server :: Server UserAPIserver = return users : 〈|〉 return postsuserAPI :: Proxy UserAPIuserAPI = Proxyapp :: Applicationapp = serve userAPI servermain = run 8080 app
360
![Page 552: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/552.jpg)
Servant
type UserAPI =
"users" :〉 Get ‘[ JSON] [User ]: 〈|〉"posts" :〉 Get ‘[ JSON] [Post ]
server :: Server UserAPIserver = return users : 〈|〉 return postsuserAPI :: Proxy UserAPIuserAPI = Proxyapp :: Applicationapp = serve userAPI servermain = run 8080 app
360
![Page 553: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/553.jpg)
Servant
type UserAPI =
"users" :〉 Get ‘[ JSON] [User ]: 〈|〉"posts" :〉 Get ‘[ JSON] [Post ]
server :: Server UserAPIserver = return users : 〈|〉 return postsuserAPI :: Proxy UserAPIuserAPI = Proxyapp :: Applicationapp = serve userAPI servermain = run 8080 app
360
![Page 554: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/554.jpg)
Servant
Jak se zeptat na API?
users : 〈|〉 posts = client userAPI
Použití:
runClientM users(mkClientEnv
(newManager defaultManagerSettings)(BaseURL Http "userdb.cz" 8080 "")
)
:: IO [User ]
361
![Page 555: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/555.jpg)
Servant
Jak se zeptat na API?
users : 〈|〉 posts = client userAPI
Použití:
runClientM users(mkClientEnv
(newManager defaultManagerSettings)(BaseURL Http "userdb.cz" 8080 "")
)
:: IO [User ]
361
![Page 556: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/556.jpg)
Servant
Jak se zeptat na API?
users : 〈|〉 posts = client userAPI
Použití:
runClientM users(mkClientEnv
(newManager defaultManagerSettings)(BaseURL Http "userdb.cz" 8080 "")
)
:: IO [User ]
361
![Page 557: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/557.jpg)
Servant
Jak se zeptat na API?
users : 〈|〉 posts = client userAPI
Použití:
runClientM users(mkClientEnv
(newManager defaultManagerSettings)(BaseURL Http "userdb.cz" 8080 "")
)
:: IO [User ]
361
![Page 558: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/558.jpg)
Servant
Bonusy!
Javaskriptový API klient pro jQuery:
apiJS :: TextapiJS = jsForAPI userAPI jquery
API dokumentující jiné API:
apiDocs :: APIapiDocs = docs userAPI
361
![Page 559: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/559.jpg)
Front-end
Tradiční webový front-endový jazyk je Javaskript (a moc toho s tímnenaděláme).
Haskell jde přeložit do Javaskriptu!
• GHCJS (https://github.com/ghcjs/ghcjs)• Existuje několik užitečných knihoven, např. Reflex-DOM.
362
![Page 560: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/560.jpg)
Front-end
Tradiční webový front-endový jazyk je Javaskript (a moc toho s tímnenaděláme).
Haskell jde přeložit do Javaskriptu!
• GHCJS (https://github.com/ghcjs/ghcjs)• Existuje několik užitečných knihoven, např. Reflex-DOM.
362
![Page 561: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/561.jpg)
Front-end
Méně brutální řešení:
• CoffeeScript• Elm• PureScript
(jazyky jsou občas polovičaté, ale pořád lepší než Javaskript)
363
![Page 562: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/562.jpg)
Náhled na FRP a Reflex-DOM
Funkcionální Reaktivní Programování je zajímavý způsob jak popisovatdynamicky se měnící objekty. Uživatelské interfacy jsou vhodné místo kpoužití.
• Tradičně:• getMousePos• setWidgetPosition (mousePos)
• Event-based: onMousePosChange (setWidgetPosition)
• Reaktivně: widget {position = mousePos}
364
![Page 563: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/563.jpg)
Náhled na FRP a Reflex-DOM
Funkcionální Reaktivní Programování je zajímavý způsob jak popisovatdynamicky se měnící objekty. Uživatelské interfacy jsou vhodné místo kpoužití.
• Tradičně:• getMousePos• setWidgetPosition (mousePos)
• Event-based: onMousePosChange (setWidgetPosition)
• Reaktivně: widget {position = mousePos}
364
![Page 564: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/564.jpg)
FRP modeluje data programu jako chování (Behavior), cožje abstrakce celého průběhu hodnot v čase běhu
programu.
To samozřejmě nejde. Budeme říkat, že to je ‘implementační detail’.
364
![Page 565: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/565.jpg)
FRP modeluje data programu jako chování (Behavior), cožje abstrakce celého průběhu hodnot v čase běhu
programu.To samozřejmě nejde. Budeme říkat, že to je ‘implementační detail’.
364
![Page 566: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/566.jpg)
FRP demo
{-# LANGUAGE OverloadedStrings #-}import Reflex.Dom
main = mainWidget $ el "div" $ dot← inputElement "default1"t2← inputElement "default2"dynText $ _inputElement_value t
� ", " �_inputElement_value t2
(kód je zjednodušený)
365
![Page 567: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/567.jpg)
data InputElement er d t= InputElement{_inputElement_value :: Dynamic t Text, _inputElement_checked :: Dynamic t Bool, _inputElement_checkedChange :: Event t Bool, _inputElement_input :: Event t Text, _inputElement_hasFocus :: Dynamic t Bool, _inputElement_element :: Element er d t, _inputElement_raw :: RawInputElement d, _inputElement_files :: Dynamic t [RawFile d ]
}
Nějakou jednodušší variantu FRP dozajista čeká zářivá budoucnost.
366
![Page 568: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/568.jpg)
data InputElement er d t= InputElement{_inputElement_value :: Dynamic t Text, _inputElement_checked :: Dynamic t Bool, _inputElement_checkedChange :: Event t Bool, _inputElement_input :: Event t Text, _inputElement_hasFocus :: Dynamic t Bool, _inputElement_element :: Element er d t, _inputElement_raw :: RawInputElement d, _inputElement_files :: Dynamic t [RawFile d ]
}
Nějakou jednodušší variantu FRP dozajista čeká zářivá budoucnost.
366
![Page 569: Programování v Haskellu - Univerzita Karlovakratochvil/haskell/slides.pdf• návrhové vzory z funkcionálního programování a Haskellu jsou jedny z nejmladších a nejužitečnějších](https://reader030.vdocuments.mx/reader030/viewer/2022040209/5e3870947389a62f4805c659/html5/thumbnails/569.jpg)
Konec!
366