Protože jsem se nedávno s kýmsi bavil o jazyku Erlang (v souvislosti s tím, že je v něm napsaný údajně nejvýkonnější existující webserver Yaws), pár dní jsem se tímto jazykem zabýval, protože jsem na to při „našem prvním setkání“ neměl příliš času.
Erlang původně vyvinula firma Ericsson pro ovládání telefonních ústředen, a to před více než 15 lety. Dnes je Erlang spravován open source komunitou a je pochopitelně k dispozici zdarma pro všechny myslitelné platformy. Pár základních informací je v tomto roztomilém starém videu, které upozorňuje na některé z hlavních přednosti Erlangu:
Na oficiálních stránkách je k Erlangu podrobná dokumentace, kterou není problém přečíst a pochopit (samotné jádro jazyka je poměrně jednoduché, všechno ostatní je v knihovnách a ty jsou napsány převážně v Erlangu, takže je můžete studovat). Základní problém, bránící většímu rozšíření Erlangu, je ale podle mě v tom, že i když pochopíte syntaxi a princip jazyka, nepochopíte, k čemu vám to všechno může být dobré a bude vám to připadat jako šílenost.
K „bizarním“ vlastnostem tohoto funkcionálního jazyka patří například:
Na pointu těchto zdánlivě zvláštních pravidel přijdete až po nějaké době aktivního používání jazyka. Většina těchto omezení je totiž v jazyce proto, aby vás nutila programovat jistým způsobem, který je náročnější na přemýšlení, ale jehož výsledkem je přehlednější, robustnější a 5× až 10× kratší kód než ve většině ostatních jazyků!
Erlang je nejideálnější pro programování systémů pracujících v reálném čase, tady např. serverů nejrůznějšího druhu. U erlangových aplikací není výjimkou, že v nich běží současně stovky a tisíce procesů (což nejsou „procesy“ v klasickém smyslu toho slova, ale jednoduché erlangovské „miniprocesy“) a celá aplikace se vlastně skládá ze stovek a tisíců miniaturních serverů a klientů! Dovolte příklad:
Dejme tomu, že potřebujete mít nějakou globální datovou strukturu, ke které musí mít přístup různé rutiny vaší aplikace. V tradičnějších jazycích by se přístup k těmto datům řešil pomocí zámků, semaforů apod. V Erlangu je nejelegantnějším řešením vytvořit server, který se bude starat pouze o tuto strukturu (jiný proces se k ní nemůže nijak dostat) a jemuž budou ostatní části programu zasílat dotazy jako „Jaké telefonní číslo má Josef Novák?“, „Změn telefonní číslo Josefa Nováka na 609 696969“ nebo „Vymaž všechny Nováky“. Na rozdíl od ostatních jazyků tuto meziprocesovou komunikaci v Erlangu vytvoříte naprosto triviálně (systém se automaticky stará o buffering, timeouty a podobné věci) a dokonce není nejmenším problémem, aby různé procesy běžely na různých fyzických počítačích (na principu jejich programování se tím nic nemění)!
Erlang má vlastní interaktivní shell, který pro nováčka vypadá dost strašidelně, ale jeho síla je v tom, že si ho snadno přizpůsobíte a vytvoříte si vlastní vývojové prostředí. Já jsem si například během prvního dne experimentování napsal vlastního démona, který při mém programování sleduje erlangovské zdrojáky v daném adresáři, automaticky pozná pokud se některý z nich změní a v takovém případě daný modul odstraní z běžícího systému, nahradí nově zkompilovanou verzí (pokud v ní nejsou chyby) a restartuje moji aplikaci (aniž bych musel opouštět textový editor, ve kterém pracuji). To vše je naprogramováno v pár řádcích a vůbec to nepůsobí dojmem nějaké „prasárny“ (jak by to působilo v jiných jazycích, které podobné věci také umí).
Pokud vás tenhle krátký úvod zaujal, v Erlangu je napsán například Jabber server eJabberd a 3D modelovací program Wings3D, přičemž zdrojový kód obou je překvapivě krátký a přehledný a v obou případech ho můžete volně studovat, protože jde o open source aplikace.
Sice po asi roce, ale přece. Tak nevím jestli mám FF tykat, ale asi jo. Ten loader je hezkej. Jen taková drobnost, když si přečteš Making Reliable Systems with Presence of Software Errors od Joe Armstronga a kriticky se podíváš na ten svůj výtvor tak je to pěkné až na jednu věc. Bez put a get by to bylo hezčí :-) Jde čistě jen o to, že to není úplně čisté. Krom toho na přepnutí na nový kód není potřeba ten starý purgovat, stačí když se zavolá plně kvalifikovaná funkce a už to běží na novém kódu. Tedy překompiluješ a můžeš na to zapomenout, dřív nebo později všechny běžící procesy migrtují na nový kód.
-module(starter).
-export([stop/0, start/0, restart/0, bootup/1]).
%% called after recompilation
restart() -> test:run().
stop() ->
case is_pid(whereis(starter)) of
true ->
starter ! stop,
stopped;
_Else ->
already_stopped
end.
start() ->
case stop() of
stopped -> io:format("Starter stopped.~n");
already_stopped -> true
end,
io:format("Starting starter~n"),
Pid = spawn_link(?MODULE, bootup,["."]),
register(starter, Pid).
bootup(Dir) ->
loop(Dir, 2000, none).
loop(Dir, Delay, Modifs) ->
receive
stop ->
exit(normal);
recompiled ->
?MODULE:restart()
after Delay ->
% io:format("watching dir ~p...~n",[Dir]),
Files = filelib:wildcard("*.erl",Dir),
NewModifs = lists:map(fun(File) -> {File, filelib:last_modified(File)} end,Files),
% io:format("---~p~n",[Modifs]),
case NewModifs == Modifs of
true -> true;
false -> recompile(Files)
end
end,
loop(Dir, Delay, NewModifs).
recompile(Files) ->
Recompile = fun(File) ->
Result = compile:file(File),
% Result = code:load(File),
io:format("Compiled: ~p~n",[Result]),
case Result of
{ok, Module} when Module /= starter -> code:purge(Module), code:delete(Module);
_ -> ok
end
end,
lists:foreach(Recompile, Files),
io:format("---Recompiled~n"),
starter ! recompiled.
Tak odladěno a vyzkoušeno. Zajímavé, že mě nenapadlo si takovou věcičku taky udělat. Jen tak pro ty rozumbrady aka Dusek. Jen si zkuste napast něco co si skompiluje novou verzi sebe sama a bez přerušení činnosti pokračuje s novou verzí kódu. V erlangu brnkačka viz následující kód.
Pročištěná verze:
-module(starter).
-export([stop/0, start/0, loop/1]).
-define(dir, ".").
-define(timeout, 2000).
%% called after recompilation
stop() ->
case is_pid(whereis(starter)) of
true ->
starter ! stop,
stopped;
_Else ->
already_stopped
end.
start() ->
case stop() of
stopped -> io:format("Starter stopped.~n");
already_stopped -> true
end,
io:format("Starting starter~n"),
Pid = spawn_link(?MODULE, loop,[{?dir, ?timeout, none}]),
register(starter, Pid).
loop({Dir, Delay, Modifs}=S) ->
receive
stop ->
ok;
_ -> loop(S)
after Delay ->
% io:format("watching dir ~p...~n",[Dir]),
Files = filelib:wildcard("*.erl",Dir),
NewModifs = lists:map(fun(File) -> {File, filelib:last_modified(File)} end,Files),
% io:format("---~p~n",[Modifs]),
case NewModifs == Modifs of
true -> loop(S);
false -> recompile(Files),
?MODULE:loop({Dir, Delay, NewModifs})
end
end.
recompile(Files) ->
Recompile = fun(File) ->
Result = compile:file(File),
io:format("Compiled: ~p~n",[Result]),
case Result of
{ok, Module} -> code:purge(Module),
code:delete(Module),
code:load_file(Module);
_ -> ok
end
end,
lists:foreach(Recompile, Files),
io:format("---Recompiled~n").
Zdroják na ten loader / unloader by náhodou nebyl? Rád bych do něj nahlédnul.
Jinak, co se týče těch vlastností Erlangu, pravděpodobně je spíše ocení někdo, kdo má alespoň základní znalosti nějakého funkcionálního jazyka. Předpokládám, že většina vysokoškolsky vzdělaných lidí v oboru IT zná aspoň trochu Lisp, když už nic. Takže bych to neviděl tak beznadějně. ;-)
[3]:<pre>-module(starter).
-export([stop/0, start/0, restart/0, bootup/1]).
%% called after recompilation
restart() -> test:run().
stop() ->
case is_pid(whereis(starter)) of
true ->
starter ! stop,
stopped;
_Else ->
already_stopped
end.
start() ->
case stop() of
stopped -> io:format("Starter stopped.~n");
already_stopped -> true
end,
io:format("Starting starter~n"),
Pid = spawn_link(?MODULE, bootup,["."]),
register(starter, Pid).
bootup(Dir) ->
put(dir, Dir),
put(delay, 2000),
put(modifs, none),
loop().
loop() ->
receive
stop ->
exit(normal);
recompiled ->
?MODULE:restart()
after get(delay) ->
% io:format("watching dir ~p...~n",[get(dir)]),
Files = filelib:wildcard("*.erl",get(dir)),
Modifs = lists:map(fun(File) -> {File, filelib:last_modified(File)} end,Files),
% io:format("---~p~n",[Modifs]),
case put(modifs, Modifs) == Modifs of
true -> true;
false -> recompile(Files)
end
end,
loop().
recompile(Files) ->
Recompile = fun(File) ->
Result = compile:file(File),
% Result = code:load(File),
io:format("Compiled: ~p~n",[Result]),
case Result of
{ok, Module} when Module /= starter -> code:purge(Module), code:delete(Module);
_ -> ok
end
end,
lists:foreach(Recompile, Files),
io:format("---Recompiled~n"),
starter ! recompiled.</pre>
Neřekl bych, že nikdo. Např. Linspire používá nějakou dobu Haskell jako hlavní vývojový prostředek pro svoje nástroje, některé prvky funkcionálního programování jsou často používané např. programátory Pythonu. Docela dost lidí používá MLDonkey napsaný v OCAML. No a samotný Erlang se samozřejmě používá taky. ;-)
12> Přinejmenším se člověk naučí myslet jinak než procedurálně. Mám jeden semestr funkcionálního programování za sebou a i když se jen těžko objektivně posuzuje, jestli mi ty znalosti vysloveně pomáhají v praxi, řekl bych že jo. Člověk se naučí běžně zacházet s rekurzí a některé funkcionální konstrukce se dají použít v Perlu, Pythonu, JavaScriptu nebo XSL.
No ... tyhle funkcionalni jazyky jsou sice pekny na hrani, ale pro realny pouziti (mozna s vyjimkou nejakejch specialnich vypoctu) jsou podle me naprosto k nicemu.
Vytvoreny kod v podstate neni mozne udrzovat a silne pochybuju, ze by se v nem vyznal nekdo jiny nez autor.
Ano, vysledny kod je sice kratsi, ale kdo se ma vyznat v konstrukcich typu : podle vysledku rek. volani zavolej jeste jednou sama sebe s parametrem jako vysledkem jeste jednoho rek. volani. (nekecam, opravdu jsem to v jednom programu potreboval). ... predstavte si potom jak, kdyz mate kod, prijit na to, co to dela ...
(znam jenom Hasskell, mozna Erlang bude pouzitelnejsi)
Ehm, pokud jsou funkcionalni jazyky tak "nepochopitelne" a "neuzitecne", tak proc je microsoft ochotne vykrada do sveho ce sharp? (a nerekne tvurcum puvodnim napadu ani diky)
Anonymni funkce a closures, automaticka inference (odvozeni) typu, to bude v dalsi verzi microsoftiho jazyka. Java chysta neco podobneho.
Samozrejme tomu bude Microsoft rikat nejakou svoji prihlouplou manazerskou hantyrkou a za dva roky to bude umet kazdy "Visual" vidlak a propagandisti z Microsoftu o tom budou extaticky vykrikovat na svych blozich coze prevratneho zase vymysleli.
Chytri programatori jako je Frantisek a ja ovsem tohle zname a pouzivame uz dnes.
Mimochodem, cely humbuk kolem webovych sluzeb a posilani zprav ("enterprise", XML, blablabla) je vlastne opakovanym vynalezanim Erlangu - paralelni zpracovani s komunikaci pomoci zprav.
NecoOTomVim: Ale spis min nez vic :) Podobny problem se resi uz dlouho, existuje x ruznych objektovych reseni, ale az XML webove sluzby odbourali zbytecne technologicke naroky na strane integrovanych systemu / procesu. Muzu nejak jednoduse zavolat proces Erlangu z libovolne jine platformy, kdyz jsou XML webove sluzby jen opakovanim jeho funkcnosti? Pokud ano, dalo by se uvazovat o tom ze XML webove sluzby by mohli byt nahrazeny Erlangem, jinak je to jen jedno z milionu kvalitnich sudlitek pro homogenni prostredi, pro heterogenni prostredi jsou tu vyborne XML webove sluzby.
Taky nemam rad buzzwords, ale je potreba rozlisovat kdy se za nimi skryva skutecne uzitecna technologie...
BTW, to ze nekdo vykrada funkcnosti z funkcionalniho jazyka do objektoveho jazyka o kvalite toho funkcionalniho jako celku nerika vubec nic :) Cimz samozrejme netvrdim ze kvalitni neni.
[19]
Dobre, dve malo zname pravdy:
XML je zvast a XML webove sluzby jeste vetsi. Naucte se Lisp a pi-calculus a Erlang, pochopite principy a to je dulezitejsi nez reklamni blaboleni dobre placenych konzultantu a jine pakaze.
> Ad "nekdo vykrada funkcnosti z funkcionalniho jazyka do objektoveho jazyka o kvalite toho funkcionalniho jako celku nerika vubec nic :)"
Ale rika. Obtizne problemy (jako je garbage collection, napojeni na imperativni prostredi atd.) vyresi nektery akademik ve funkcionalnim jazyku a kvalitne to popise ve sve prednasce, dobre placeny zvanil od javy nebo od microsoftu si to poslechne a pak udela to same pod jinym nazvem.
Je to smutne, ale je to tak.
[20] Pletete hrusky s jablkama :) Znovu a pomaleji: jak mi pomuze Lisp a pi-calculus a Erlang vyresit integracni problemy ktere resi XML webove sluzby? Zatim mam dojem ze o XML webovych sluzbych vite jen prave to co placaji marketingovy manazeri. Tentokrat prosim konkretni odpoved, ne nadavani na uspesnejsi konzultanty :)
Pokud vim, na posilani zprav byl zalozeny uz SmallTalk, coz je (pokud se nemylim) rok 1975.
Jinak v programovani nebyva problemem ani tak pocet radku, ale zejmena udrzovatelnost. A tady musim souhlasit s [15], ze to neni silna stranka funkcionalnich jazyku. To, ze se eventuelne nejake konstrukce prenasi do imperativnich jazyku neznamena, ze jsou lepsi (protoze resit co je "lepsi" je vpodstate nesmysl), ale ze se mohou obcas hodit.
[21] Vy zase pletete dohromady principy a jejich konkretni implementaci.
Jeste jednou a poomalu.
Pi-calculus a Erlang vas nauci premyslet o paralelnich procesech ktere komunikuji pomoci zprav, a tyto znalosti pak muzete v omezene mire pouzit ve svete webovych sluzeb (bohuzel neni nic lepsiho).
Tak dóst, tohle nikam nevede. Webové služby možná řeší jen vzájemnou komunikaci, ale to kvůli tomu, že nic jiného řešit nechtěly. XML je praktická věc, stačí se rozhlédnout kolem. To, že nějaké technologie nabízely funkce podobné XML už dřív, na užitečnosti a úspěchu XML vůbec nic nemění. Proč by XML saláti měli vědět něco o paralelním programování nevím… Každá technologie má své výhody a nevýhody, a ne vždycky vyhraje ta „technicky nejlepší“. Nebylo by dobré se s tím smířit?
[25, 26] Preju Vam, aby se Vam v nejblizsi dobe podarilo ziskat trochu nadhledu z vyssi perspektivy, bez toho takhle dalekosahle soudy o technologiich, ktere vyvolaly tuhle debatu opravdu delat nejdou. Kazdopadne tahle diskuse pro me po "argumentu" [25] ztratila jakykoliv smysl a dal ji nebudu marnit cas :)
Vše je řečeno na www.fuxoft.cz
Přečteno 93 370×
Přečteno 85 144×
Přečteno 42 678×
Přečteno 41 827×
Přečteno 37 972×