Nová láska Haskell

cs v kategorii code • 7 min. čtení
Mind the age! Most likely, its content is outdated. Especially if it’s technical.

Už tomu jsou dva roky, co jsem si řekl, že chci poznat svět funkcionálního programování. O Haskellu jsem slyšel, že je to ten správný výběr, ale akademický. Takže jsem sáhl po jednom z těch populárnější, Scale. Zkusil jsem si kurz na Courseře a… no, nedokončil jsem. Scala mi nějak k srdci nepřirostla. Nebavilo mne v ní programovat. Asi tam na mne bylo stále moc Javy a málo prostoru pro funkcionální styl. Takže jsem přeci jen nakonec skončil u Haskellu.

Začít se učit funkcionální styly v Haskellu pro jeho puričnost je náročné. Několikrát mi málem explodovala hlava, jak je vše úplně jinak, než jsem doposud znal. Ale přežil jsem a jak se říká, co tě nezabije… to si zamiluješ. :-)

Uvědomil jsem si to ve chvíli, kdy jsem napsal Pytohní kód, který na mne zařval výjimkou. Že prý druhý řádek není callable…

ZeroDict = defaultdict(lambda: 0)
d = ZeroDict({'a': 1, 'b': 2})

Aneb technika známá jako partial application ve funkcionálním světě. Každá funkce bere ve skutečnosti pouze jeden parametr, což se v Haskellu velmi často prakticky využívá.

Jakmile jsem chybu opravil, zařvalo na mne NoneType object has no … Něco, co se mi v Haskellu nemůže stát. Prázdná hodnota totiž neexistuje. Pokud se může něco pokazit, musí se taková událost explicitně vyjádřit. Což může znít děsivě, ale díky monádám (žádný strach) se kód neprasí samými podmínkami a pracuje se s ním mnohem lépe.

Například jsem si udělal jednoduchý RSS a Atom parser. Samotné poskládání dílčích celků dohromady vypadá nějak takto:

getSourcesFromDatabase >>= fetchFeeds >>= mapM createQuery >>= commitQueries

A pokud se něco po cestě pokazí, script nespadne. Normálně doběhne a každá část se může rozhodnout, jak se situací naložit. Může to znít, že nakonec ty podmínky oddře spodnější vrstva. Ano, musí se kód přizpůsobit, každopádně sám jsem podmínku v Haskellu nepoužil. Žádnou! Aspoň ne v podobě, jakou ji běžně známe. Ani cyklus.

Další skvělá věc je totiž pattern matching. Dalo by se to lehce přirovnat k overloaded funkcím na steroidech. Příklad k parsování RSS či Atom feedu (pro lepší pochopení: vstup je seznam tagů jak jdou za sebou v XML struktuře, včetně komentářů či textu):

parseFeed :: Tags -> Maybe Feed
parseFeed [] = Nothing
parseFeed ((TagOpen "rss" _):tags) = parseRss tags
parseFeed ((TagOpen "feed" _):tags) = parseAtom tags
parseFeed (_:tags) = parseFeed tags -- Skip XML declaration and comments at the beggining.

Hledá se známý tag rss či feed a podle toho se provede další parsování. Jinak se pokračuje dál. A pokud nenajde, vrátí se Nothing, což je možná hodnota typu Maybe. Při použití se pak musí s takovou možností explicitně počítat. Ale jak bylo vidět výše, monády (což není nic jiného, než design pattern) to podstatně zjednodušují.

Navíc vše je krásně vidět, čímž mám na mysli typy. Haskell je velice chytrý a umí si typy téměř vždy odvodit sám. Ale mohu mu je předat a pomoct si tak při debugování. Jinými slovy Haskell je silně typový, ale zároveň nehází programátorovi klacky pod nohy.

Na Haskellu je hezká další věc, na kterou nemám vhodnou ukázku, takže si půjčím jak najít pravoúhlý trojúhelník s obvodem 24 jednotek z Learn You a Haskell for Great Good:

ghci> let allTriangles = [(a,b,c) | c <- [1..], b <- [1..c], a <- [1..b]]
ghci> let solutions = filter (\(a,b,c) -> a^2 + b^2 == c^2 && a+b+c == 24) allTriangles
ghci> take 1 solutions
[(6,8,10)]

A to, že se problémy neřeší zapsáním algoritmu, ale matematickým zápisem – udělá se množina možných řešení (klidně nekonečných) a aplikují se různé transformace, kterými se odfiltrují nevhodná. Až zůstanou jen ta správná řešení.

Hm, opravdu nekonečných? No jasně! Však se mrkněte na ukázku, konkrétně právě [1..] generuje čísla do nekonečna. Haskell je totiž, jako správný programátor, lazy. Dokud nemusí, nic neprovede. Pokud spustíte dlouho trvající (či nekonečnou) funkci, ale nepoužijete její výsledek, Haskell ji vůbec nevykoná. Což pak otevírá spoustu zajímavých možností řešit úkoly s nekonečnem. Jako třeba tu, kde chci jen první řešení, takže jakmile se najde, zbytek se vůbec nevyhodnotí.

Bohužel to taky má své stinné stránky. Sice to v některých případech oproti ostatním jazykům problémy řeší, v jiných naopak je potřeba dávat velký pozor. Aby něco takového fungovalo, musí si Haskell pamatovat stack, jak v případě potřeby danou hodnotu vypočítat. Což u velkých struktur může znamenat stack overflow. Tedy programátor na to musí myslet a na správných místech použít ty správné funkce či jinak vynutit vypočítat hodnotu, protože to je na nějakém místě prostě efektivnější.

Abych to shrnul: nikdy jsem si nemyslel, že se mi bude líbit jazyk, kde nejsou podmínky, cykly a prázdné hodnoty. Přišlo mi něco takového jako bláznovství. Ale po seznámení s Haskellem se mi takové praktiky opravdu líbí. Bohužel si myslím, že díky puričnosti, za což je často odsuzován, se do praxe moc nedostane. Ale osobně se mi to, překvapivě, opravdu líbí. Myslím si, že právě striktní oddělení pure funkcionálních funkcí dává méně prostoru pro chyby.

Mimochodem v Haskellu nejde debugovat s print příkazy jako třeba v Pythonu. Nejlepší způsob jsou testy. Takže mne to hezky nutí co nejvíce kódu umístit do lehce testovatelných pure funkcí a psát řádné testy vždy při vývoji, nikoliv až potom. A tím jsem zjistil, že TDD je pouze mentální switch. Nijak to nekomplikuje práci, je potřeba si na takový postup pouze zvyknout.

Pokud se chcete na Haskell také podívat, doporučuji tyto zdroje:






8 reakcí

Co říkáte na jazyk F#? Sice je platformově závislý, ale osobně se mi líbí víc než Scala nebo Closure.

Haskell je mrcha nevěrná :), vždy se k němu ale rád vracím, nutí mě přepnout v hlavě na jiné řešení problémů a pomáhá mi lépe postavit algoritmy v nízkoúrovňových jazycích. Rád v něm řeším programátorské úlohy nebo prototypuji.

@yemanresuy Po zklamání se Scalou jsem se rozhodl jít do něčeho léty prověřeného. Takže o F# nic moc nevím, jen to, že toho má na první pohled taky až moc (tj. ne jen funkcionální prvky).

@Tomáš Ano, asi to nebude jazyk na full-time, ale určitě si s ním budu taky hrát. Pomáhá mi se na různé věci dívat jinak. :-)

Díky za článek. S na Haskell se taky chystám, ale teď jsem začal s Clojure (nadšení neopadlo!). Jen dodám, že Python má partials a pattern matching (ne nativně) taky. S tím lazy bývá ještě problém, že se může hodně náročných operací odsunout na "později" a všechny se pak mají vykonat v jeden okamžik a dojte ti paměť.

@Lukáš Vím, občas partials taky v Pythonu využiji. Ale co si budeme povídat, není to ono a vypadá to tam vetřelsky. :-) Jinak díky za připomenutí, že nemusí dojít pouze ke stack overflow, ale taky se může zahltit tím, že se vše nechá na jeden okamžik.

Diky za clanek, v Cechach se toho clovek o haskellu moc nedozvi, zaslouzil by vic pozornosti.

Cis194 v updatovane verzi oproti linku v clanku (https://www.seas.upenn.edu/~cis194/lectures.html)

Laziness muze byt mrcha, proto je taky moznost striktni evaluace (info treba zde https://www.seas.upenn.edu/~cis194/lectures/06-... nebo https://wiki.haskell.org/Foldr_Foldl_Foldl').

Debugovani s printem (https://hackage.haskell.org/package/base-4.8.1....).

Ja naopak doufam, ze haskell nekdy na full time delat budu. Takze az rozjedete haskellovej projekt v seznamu tak dej vedet :)

Díky, updatoval jsem link na Cis194 i v článku. :-)

Co se týče informací v Česku, mám chuť to změnit. Ale zatím, i když si s ním téměř dva roky hraji, se stále necítím, že bych tomu rozuměl natolik dobře, aby mé texty byly přínosem. A hlavně nechci napsat jen nějaký tutoriál, kterých je v angličtině spousta. No, uvidíme, co, zda vůbec, ze mne vypadne. :-)

Jinak přijď. Třeba se nám povede na něčem Haskell zavést. Přeci jen bez lidí se to moc nezmění. :-)

Ahoj, shanim lidi, kteri chteji delat Haskell na fulltime. trin.cz@gmail.com





Může se vám také líbit

en Makefile with Python, November 6, 2017
en Fast JSON Schema for Python, October 1, 2018
en Deployment of Python Apps, August 15, 2018
cs Jasně, umím Git…, August 6, 2014
cs Checklist na zabezpečení webových aplikací, March 1, 2016

Další články z kategorie code.
Nenechte si ujít nové články díky Atom/RSS kanálu.



Poslední příspěvky

cs Mami, tati, přejde to, December 9, 2023 in family
cs Co vše bychom měli dělat s dětmi?, November 24, 2023 in family
cs O trávicí trubici, November 7, 2023 in family
cs Na šestinedělí se nevyspíš, October 28, 2023 in family
cs Copak to bude?, October 20, 2023 in family