Happstack: část první

Webový framework Happstack je postaven na funkcionálním jazyce Haskell. Vývoj webových aplikací pomocí jazyka deklarativního paradigmatu je pro běžného vývojáře něčím těžko představitelným. V tomto miniseriálu si proto společně ukážeme základní koncepty a naučíme se vytvářet jednoduché aplikace.
Seriál: Happstack: Webový framework v Haskellu (3 díly)
- Happstack: část první 19. 5. 2010
- Happstack: část druhá 26. 5. 2010
- Happstack: část třetí 2. 6. 2010
Nálepky:
Většina webových aplikací je napsána v nějakém z imperativních jazyků. Nezáleží na tom, zda-li se jedná o PHP, Javu, či cokoliv jiného, tyto jazyky fungují na principu vykonávání sekvence příkazů (imperativů). Kód takového jazyka se tak podobá receptu: přiřaď tuhle hodnotu sem, pokud se rovná jiné hodnotě, vynásob ji a výsledek ulož tam, jinak udělej něco jiného. Oproti tomu deklarativní jazyky pouze zavádí (deklarují) určitá tvrzení, kterými se překladač při vyhodnocování řídí. Kód funkcionálních jazyků se tak často podobá matematickému předpisu: faktoriál přirozeného čísla většího než nula se rovná násobku faktoriálu čísla o jedno menší, jinak se rovná jedničce.
Současným trendem je přejímání některých funkcionálních prvků do imperativních jazyků, protože mohou výrazně zkrátit a zpřehlednit kód. Možná používáte anonymní funkce v JavaScriptu, generátory seznamů v Pythonu, nebo funkce vyššího řádu v Ruby, aniž byste tušili, že pochází z funkcionálního světa. Proto znalost funkcionálního programování rozhodně není na škodu a může vám pomoci stát se lepším programátorem v konvenčnějších jazycích. Kromě toho existuje nejeden úspěšný webový projekt, jenž byl napsán v nějakém z funkcionálních jazyků, což popisuje kupříkladu Paul Graham ve svém článku Beating the Averages.
Seznamte se, Haskell
Haskell je čistě funkcionální jazyk, který je staticky typovaný, referenčně transparentní a jeho kód se vyhodnocuje líně. Při programování ve frameworku Happstack se bez jeho znalosti neobejdeme. Jako lehký úvod do tohoto jazyka může sloužit seriál Petera Almásyho Haskell a funkcionalní programování, pro bezbolestné pochopení základů doporučuji tutoriál Naučte se Haskell! a praktičtější příklady přináší kniha Real World Haskell, která je k dispozici zdarma online.
Pokud jste, stejně jako já, spíše praktičtěji zaměření, určitě vás bude zajímat, jak je na tom Haskell s rychlostí, stabilitou a rozšířeností. Mnoho zajímavých jazyků je v praxi obtížně nasaditelných, protože nepodávají dostatečný výkon, jejich implementace jsou neúplné či chybové, případně pro ně vůbec neexistuje použitelný překladač pro požadovanou platformu. Haskell prošel již poměrně dlouhým vývojem (jeho počátky sahají do konce osmdesátých let), jeho překladač GHC je stabilní, podporuje nativní překlad jak pro systémy založené na Unixu, tak pro Windows, a výkonnostně je na tom velice dobře (viz např. The Computer Language Benchmarks Game).
Alternativy k Happstacku
Happstack není jediným zástupcem svého druhu. V Haskellu je napsáno několik dalších knihoven pro vývoj webových aplikací. Příkladem může být framework Turbinado, který se v lecčem podobá Ruby on Rails či Djangu, jenže ten byl nedávno opuštěn hlavním vývojářem a tím pádem se přestal vyvíjet. I samotný Happstack měl podobný osud — jeho kód vychází z frameworku HAppS, jenž byl taktéž zanechán svému osudu. Autoři nejspíše psaní frameworku brali jako výzvu a po dotažení do použitelné podoby ztratili zájem o další rozšiřování. Kromě těchto dvou frameworků existuje spousta dalších, jejichž nekompletní seznam lze nalézt, spolu s popisem haskellových webových serverů a dalších užitečných knihoven, na HaskellWiki.
Instalace
Haskell má vlastní instalační systém Cabal. Ten umožňuje jednoduchou instalaci bez nutnosti programy překládat ručně. Ovládá se přes rozhraní Cabal-install. Pro zprovoznění tohoto systému je třeba mít nainstalovaný překladač GHC (nejlépe nejnovější verze) společně s Haskell Platform, což je sada nejčastěji používaných rozšiřujících knihoven Haskellu, mezi nimiž se nachází i Cabal.
~/.cabal/
. Nachází se tam i adresář bin
, který je třeba přidat do proměnné prostředí PATH
, kupříkladu připsáním řádku export PATH="$PATH:$HOME/.cabal/bin"
na konec souboru ~/.bashrc
.
Jakmile máme Cabal funkční, stačí nám zadat do příkazové řádky tyto příkazy:
$ cabal update
Downloading the latest package list from hackage.haskell.org
$ cabal install happstack
Resolving dependencies...
...
Příkaz cabal update
získá aktuální seznam balíčku z repozitáře Hackage, příkaz cabal install happstack
automaticky stáhne a nainstaluje balíček happstack včetně jeho závislostí. Pokud z nějakého důvodu automatická instalace přes Cabal nefunguje, musíme si stáhnout balíčky ručně, rozbalit je, a pomocí této trojice příkazů nakonfigurovat a přeložit:
$ runhaskell Setup configure
$ runhaskell Setup build
$ runhaskell Setup install
Tento postup je zdlouhavý a nedoporučuje se, protože Happstack závisí na mnoha jiných balíčcích. Ať už jsme nainstalovali modul Happstack jakýmkoliv způsobem, jeho funkčnost ověříme napsáním příkazu happstack
:
$ happstack
Usage: happstack <command>
Possible commands:
build auto <buildCmd> <binPath> <binArgs>...: invoke the auto-builder
new project <dir>: create a new happstack project
Pomocný příkaz happstack
slouží k ulehčení zakládání a sestavování projektů Happstacku, což jsou vlastně jenom adresáře s předpřipravenými daty. My si vytvoříme svůj vlastní adresář, kam umístíme svůj první program.
Náš první program
Konvence stanovuje hlavní soubor projektu pojmenovávat jako Main.hs
. Do tohoto souboru napíšeme tento jednoduchý kód:
module Main where import Happstack.Server main :: IO () main = simpleHTTP nullConf $ return "Ahoj světe!"
V kódu importujeme modul Happstack.Server
obsahující funkci simpleHTTP
, jenž spouští webový server na výchozím portu 8000. První parametr této funkce je konfigurační struktura (datový typ Conf
), druhý parametr je samotný aplikační kód (typu ServerPartT IO
). Tato ukázka vrací na každý dotaz text Ahoj světe!, a protože je to parametr typu IO
, používá funkci return
. Happstack se standardně dodává s vlastní implementací webového serveru.
Když soubor uložíme, spustíme v příkazovém řádku příkaz runhaskell Main
a zadáme do prohlížeče adresu http://localhost:8000/, zobrazí se nám v něm text. Stisknutím klávesové zkratky Ctrl + C můžeme spuštěný server ukončit a program si přeložit do binárního kódu:
$ ghc --make Main
[1 of 1] Compiling Main ( Main.hs, Main.o )
Linking Main ...
Vytvoří se nám soubor Main
, který spustíme pomocí příkazu ./Main
. Pro vývoj a testování je lepší nečekat, než se kód přeloží, ale spouštět si zdrojový kód příkazem runhaskell
, kdežto pro nasazení je lepší mít kód již přeložený.
Nasazení pomocí FastCGI
Vestavěný webový server je poměrně rychlý, ale nepoužívá vlákna. Jestliže na náš server míří velké množství HTTP požadavků, jejich obsloužení nemůže probíhat paralelně a tím pádem narůstá doba odezvy. V reálném světě by tedy těžko obstál. Pomocí balíčku happstack-fastcgi máme možnost Happstack propojit s knihovnou FastCGI, která běží pod Apache či pod jiným webovým serverem. Před napsáním příkazu cabal install happstack-fastcgi
je nutné nainstalovat vývojové soubory FastCGI (v Debianu se jedná o balíček libfcgi-dev
). Poté v našem programu provedeme několik změn:
module Main where import Happstack.Server import Happstack.Server.FastCGI main :: IO () main = runFastCGIConcurrent 8 . serverPartToCGI $ return "Ahoj světe!"
Kombinace funkcí runFastCGIConcurrent
a serverPartToCGI
spustí server s osmi vlákny, přičemž aplikační kód zůstane stejný. Tento program musíme následně přeložit s parametrem pro zapnutí podpory vláken:
$ ghc -threaded --make Main.hs -o main.fcgi
[1 of 1] Compiling Main ( Main.hs, Main.o )
Linking main.fcgi ...
Pomocí parametru -o
si stanovíme název výsledného binárního kódu. Dále tuto binárku musíme propojit se serverem. Do konfigurace serveru (např. u Apache 2 to je soubor /etc/apache2/httpd.conf
) připíšeme tento kód:
<VirtualHost *:80>
FastCGIExternalServer example.cz/main.fcgi -socket example.cz/main.sock
RewriteEngine On
RewriteRule ^/(.*)$ /example.cz/main.fcgi/$1 [QSA,L]
ServerName example.cz
ServerAlias www.example.cz
DocumentRoot /var/www/
</VirtualHost>
Konfigurace nám zajistí, aby se pro doménu example.cz
, která má veškeré soubory uloženy v adresáři /var/www/example.cz/
, použil soubor main.fcgi
. Přepisování pomocí mod_rewrite nám obstarává „hezká“ URL. Po překopírování naší binárky do tohoto adresáře a restartu serveru (příkaz /etc/init.d/apache2 restart
) uvidíme na adrese http://example.cz/ opět náš text. Tedy za předpokladu, že na náš server směřuje DNS záznam example.cz
.
Související odkazy
- Oficiální web Haskellu
- Happstack Tutorial
- Dokumentace modulů Happstack.Server a Happstack.Server.FastCGI
Příště si vytvoříme obsáhlejší příklad, který bude zpracovávat data.
Rikat, ze haskel je deklarativni jazyk, je teda opravdu trochu mimo. ,,Ciste funkcionalni“ by mozna bylo lepsi.
Deklarativní paradigma jsem ve výkladu bral jako opak imperativního. Funkcionální programování je jeho podmnožinou. To, že je Haskell čistě funkcionální, neznamená, že není funkcionální nebo není deklarativní.
Popis v prvim odstavci spis odpovida jazykum logickym (napr. Prolog).
Deklarativni je taky SQL. Funkcionalni jazyky funguji jinak, napr. lambda vyrazy mi moc deklarativni neprijdou. A vubec … http://en.wikipedia.org/wiki/Programming_language_theory
Pod pojem „deklarativní programování“ spadají i jiné jazyky, než jenom Prolog a SQL. V tom vašem odkazu se o tom nic nepíše, neměl jste na mysli spíše heslo Declarative programming?
Vzhledem k tomu, že funkcionální (zejména čistě funkcionální) jazyky patří mezi deklarativní jazyky, tak mimo není ani trochu.
Podarilo sa niekomu nainštalovať happstack pomocou cabal na Ubuntu 9.10? Samotná inštalácia zlyhá kvôli (mimo iné) balíčku trhsx:
> cabal install trhsx
Resolving dependencies…
Configuring trhsx-0.2.2…
Preprocessing library trhsx-0.2.2…
Building trhsx-0.2.2…
[1 of 1] Compiling Trhsx ( Trhsx.hs, dist/build/Trhsx.o )
Trhsx.hs:1:0:
Failed to load interface for `Prelude‘:
it is a member of the hidden package `base-3.0.3.1′
it is a member of the hidden package `base‘
Use -v to see a list of the files searched for.
cabal: Error: some packages failed to install:
trhsx-0.2.2 failed during the building phase. The exception was:
exit: ExitFailure 1
Dostal sa niekto ďalej?
Balík
trhsx
je zastaralý. Současná verze Happstacku používá balíkhsx
. Pokud to při instalaci píše, že nemůže nalézt programtrhsx
, pravděpodobně není součástí proměnné$PATH
cesta$HOME/.cabal/bin
.Možná je to mnou, ale v článku mi, kromě tématu „výzvy“, chybý nějaký adekvátní důvod proč vůbec vyvíjet web aplikaci pod tímhle frameworkem, resp. ned haskelem obecně. Kromě informace, že překlad a stabilita je ok tam nevidím nic. Díky
To je pravda. Člověk může mít mnoho různých důvodů: zná už nějaký funkcionální jazyk, tak je zvědavý, jak by vývoj webových aplikací mohl v něčem takovém vypadat; má chuť se naučit něco nového a netradičního; studuje danou problematiku dlouhodoběji a chce znát její možnosti a případné hranice (což je můj případ).
V textu jsem odkazoval na článek Beating the Averages, který doporučuji k přečtení. Ovšem bavit se o přednostech a slabinách Haskellu nebo funkcionálního programování obecně mi nepřijde jako moc dobrý nápad, většinou tohle téma vyvolá flamewar.
Protože si procvičíte Haskell nebo protože se naučíte něco nového.
Kromě toho existuje nejeden úspěšný webový projekt, jenž byl napsán v nějakém z funkcionálních jazyků, což popisuje kupříkladu…
Docela by mě zajímalo, co si představujete pod pojmem funkcionální jazyk. IMO funkcionální jazyky kladou důraz na neměnitelnost dat, což se o většině Lispů říct nedá (vyjma Clojure).
Neměnitelnost dat požadují pouze čistě funkcionální jazyky, Lisp je tedy „jenom“ funkcionální.
Já jsem právě napsal „klade důraz“, čímž jsem chtěl říci, že data je sice možné měnit, ale jazyk včetně základních knihoven je uzpůsoben tak, že to ve většině případů není nutné.