Konstanta je poměrně široký pojem. Viz například wikipedia. Je sada vlastností, které se konstantám přisuzují. Jenže každý jazyk má tu sadu trochu jinou. Společným průnikem je, že po zapsání hodnoty ji nelze změnit. Což odpovídá proměnným v Erlangu. Jsou další vlastnosti typu "musí být definovány při překladu" nebo "jedná se o globální hodnotu", které ale řada jazyků nevyžaduje, takže je lze těžko vydávat za obecnou vlastnost konstant.
Osobně si myslím, že ani "proměnná" ani "konstanta" není přesný název pro to, co v Erlangu je. Měnit se moc nedá, ale také to není konstantní po celou dobu běhu programu (protože je to lokální, při každém volání dané funkce se vytváří znovu a vy tam můžete zapsat jinou hodnotu). Přijde mi, že ta věc byla v článku popsána natolik detailně, že název mohl být zvolen jakýkoliv bez rizika, že to někoho zmate. Ale nepřekvapuje mě, že někdo by chtěl použít název jiný a argumentuje nepřesností zvoleného názvu. Jenže ani ten jiný název není dost přesný.
Jenže na rozdíl od konstant to neustále zaniká a vzniká znovu, pokaždé s jinou hodnotou. Důraz ve vaší větě je tudíž na "dobu své existence", zatímco u konstant se obvykle očekává "dobu běhu programu".
Klidně tomu konstanta říkejme, ale dost lidí to zblbne, protože budou předpokládat, že je to globální a že si to hodnotu pamatuje. A ono je to lokální a hodnotu to zapomene hned jak vyskočíte z funkce.
Spíš bych řekl, že proměnné ve funkcionálních (deklarativních) programovacích jazycích znamenají něco jiného než v imperativních.
V imperativních je to symbolická adresa buňky, ve které je uložena hodnota.
Ve funkcionálních programovacích jazycích je to symbol, který zastupuje konkrétní hodnotu, která se vyskytuje ve výpočtu (něco jako proměnné v matematice - rovnice atd.).
V tom druhém případě je v zásadě úplně jedno, jestli existuje nějaká buňka v paměti, jestli se symbol vyloučí při zjednodušení výrazu atd. Prostě symbolicky popíšeme, v jakém vzájemném vztahu jsou vstupní a výstupní data a ono se to nějak vypočítá.
Tudíž bych do toho moc nepletl objekty atd., protože ten rozdíl je jinde.
To se pletete, v dobrých imperativních jazycích se již dávno nepracuje s adresami buněk nebo buňkami jako takovými, to skončilo před rokem 1995. Dnes to funguje naprosto stejně, kompilátor zpětně dedukuje myšlenky programátora a následně si implementaci těchto myšlenek udělá sám.
Koncept proměnné nutně musí být něco umožňuje změnu. Pakliže v Erlangu nebo jiném jazyku proměnné měnit nejdou, pak to nemohou být proměnné. Nejbližší programátorská záležitost která umí "single assigment" je objekt.
Nemohu souhlasit, aspoň ne bez dalšího vysvětlení.
> v dobrých imperativních jazycích se již dávno nepracuje s adresami buněk nebo buňkami jako takovými, to skončilo před rokem 1995
Sémantika je ale v podstatě stejná nebo dost podobná. Mám nějaký chlívek, který se nějak jmenuje a do něj jednou vložím jednu hodnotu a podruhé jinou. Mírnou modifikací je "přeštítkování", tj. přiřazení reference na jiný objekt původnímu jménu (nebo naopak - stejný štítek vezmu jedné hodnotě/objektu a přilepím ho jinam). U (čistě) funkcionálních jazyků to tak nefunguje - když řeknu, že x znamená tohle, tak přes to nejede vlak.
> kompilátor zpětně dedukuje myšlenky programátora a následně si implementaci těchto myšlenek udělá sám
Ano, v ideálním případě to možné je. Nicméně opět - sémantika (z pohledu programátora) je jiná.
> Koncept proměnné nutně musí být něco umožňuje změnu. Pakliže v Erlangu nebo jiném jazyku proměnné měnit nejdou, pak to nemohou být proměnné.
Ne, koncept proměnné (v matematickém slova smyslu) znamená symbol, jehož hodnotu před provedením výpočtu obecně neznáme (může se měnit).
> Nejbližší programátorská záležitost která umí "single assigment" je objekt.
Jenže objekt je právě ta hodnota a ne odkaz na ni (není to ani chlívek a ani štítek). Alespoň tak jsem pojmu "objekt" vždychky rozuměl já.
http://stackoverflow.com/questions/15653738/whats-immutable-variable-means-in-functional-programming
Všechny funkcionální jazyky mají immutable variables, Erlang vám jen nedovolí vytvořit novou proměnnou se stejným názvem, která by přestínila předchozí. V Erlangu zkrátka proměnná odpovídá matematické proměnné - "pro všechna X, pro která platí ...“. Dokud X s nesvážeme s kritériem, může nabývat libovolné hodnoty. Po svázání s kritériem (hodnotou) ji má už na trvalo. Není to imperativní model ani OOP, přijměte jiný mentální model. Funkcionální model je starší než OOP - LISP(50. léta) vs. Simula-67(1967) a Smalltalk (1970, 1980).
To, co znáte jako OOP, je stejně hybrid - imperativní programování s objekty. Ve skutečném objektovém modelu nejsou cykly ani větvení, stačí polymorfismus.
Viz rozhovor s doc. Merunkou.
http://www.comtalk.net/Squeak/5
V Erlangu můžete "přiřadit" hodnotu proměnné pouze jedno. Proč? Protože všechny ostatní varianty jsou horší! :-) Na první pohled radikální myšlenka, ale má to výhody - snadno se to paralelizuje, nemusíte nic zamykat, nikdo vám nic pod rukama nepřepíše, snadno se to ladí.
http://media.libsyn.com/media/seradio/seradio-episode89-JoeArmstrongOnErlang.mp3
Pokuste se myslet jinak.
Síla Erlangu je v tom, že místo shared state concurrency, která vyžaduje zamykání, synchronizaci a vede k dead-lockům, používá message passing concurrency, která je mnohem jednodušší. Pokud eliminujete veškerý sekvenční kód z vašeho programu, může váš program běžet stejně dobře na dvoujádrovém procesoru jako na 1024-jádrovém procesoru.
Představte si OOP, kde by každý program běžel ve svém vlastním procesu a zprávy by se mezi objekty zasílaly asynchronně. Při poslání zprávy (zavolání metody) by volající objekt nečekal až volaná metoda skončí a vrátí hodnotu. Oba objekty by běžely paralelně. Toto přesně je Erlang, jen těm objektům říká procesy.
Erlang má vlastní scheduler v userlandu. Vzhledem k tomu, že Erlang narozdíl od jádra operačního systému ví, jak velký je stav procesu v okamžiku přepnutí kontextu, nemusí strkat na stack haldy registrů, které zrovna obsahují už nepoužívanou hodnotu, uloží jen ty, co se v dané chvíli používají a tím je režie nutná na přepnutí kontextu nižší, což spolu s nižšími paměťovými nároku userland proxesů má za následek, že těch běžících Erlang procesů může být desetitisíce nebo statisíce místo stovek až tisíců. Platí se za to neoddělením paměťových prostorů procesů běžících na jednom virtuálním stroji, ale i na to snad existuje řešení — viz Erlang on Xen - http://erlangonxen.org
> muzete v Linuxu vytvorit pres 100000 procesu
Ono lepsi nez teoretizovat, je realne si to vyzkouset:
https://plus.google.com/109540561880466469418/posts/V6WohZp4zwg
Zkus si na nejake prehistoricke plecce vyrobit 50000 OS procesu a zmerit si, jak dlouho to trvalo...
Považuji, za evidentní, že hodnota, kterou 'není možné změnit' (=není proměnná), je konstantní. Nejsem si ale jist, jestli zde nejde o něco, co mě minulo. Připadá mi to jako ustálené nepřesné názvosloví, kterému ale každý rozumí (něco jako hromosvod). Možná, že se tak dají chápat proměnné z hlediska názvosloví používaného v matematice (v zápisu funkcí...). Pokud ale jde o uložení nějakých hodnot do paměti, tak je pro mě osobně (jakožto starého imperativce) daleko pravdivější a jasnější mluvit o konstantách.
A Haskel, že nemá konstanty? Uff, to jsou buď špatně všechny manuály, co jsem četl, nebo jsem nic nepochopil - já to pochopil tak, že to, co se mění, je výsledkem funkce a to, co se nemění, je konstantní hodnota. Zatím se mi zdá, že to má úplně přesně stejně jako Erlang.
Jako matematik nesouhlasím. Konstanty typu Pi nebo e mají vždy stejnou hodnotu, která nemůže být nikdy jiná.
Jako fyzik nesouhlasím. Planckova konstanta se rovněž nemůže měnit.
Jako chemik nesouhlasím. Avogadrova konstanta není něco, co by se podle potřeby nastavovalo jinak. Argument "pro danou zkumavku se ale už nemění" neberu.
A jako imperativec také nesouhlasím. Není to možné to definovat a není to globální.
Svět není černobílý. Bohužel ani "konstanta" ani "proměnná" na popsání té entity Erlangu nesedí.
Ale jo, rozumím, co chce básník říci, jenom bych do toho vůbec nezatahoval tu viditelnost - to je prostě jiná a s konstantností entity nesouvisející vlastnost. To s tím imperativcem jsem zmínil kvůli tomu, že třeba pro mne bylo klíčové si uvědomit, že v ryze funkcionálním vesmíru je všechno naprosto jinak - třeba, že je definitivní konec všem cyklům, protože prostě nemám možnost iterovat proměnnou cyklu...
Dobre to pise Pavel Tisnovsky vys - neni to nic jineho, nez pojmenovani nejake hodnoty. Jazyk nepracuje s nicim jinym, nez s nejakymi hodnotami, takze kdyz reknu
x = 3
tak to vlastne neznamena nic jineho nez "odted trojce rikej x - kdekoli napisu x, tam vraz trojku". A je uplne jedno, jestli potom napisu nekam 1+3 nebo 1+x, protoze vysledek je stejny.
U imperativnich jazyku je promenna uplne neco jineho - je to jakysi pojmenovany CHLIVECEK, do ktereho muzu davat ruzne hodnoty. V Prologu a Erlangu, ktery z nej vychazi, je to uplne jinak. Oba terminy - promenna i konstanta, jsou zavadejici.
Myslim, ze na nazvu jednoltivych 'objektu' jazyka neni nutno lpet na nejake presne definici.
Sice se uz vicemene ustalily pojmy jako 'konstanta', 'promenna' do povedomi, ale podstatne je vysvetleni jejich vlastnosti. A to je podstatne.
takze by se dalo vyjadrit:
erl.variable != php.variable
...
kazda ma jinou vlastnost
:-D
Erlang = message passing concurrency + fault tolerance + ... + pattern matching + syntaxe připomínající trochu Prolog.
S Prologem toho má společného jen málo, nicméně Joe Armstrong měl rád Prolog, když Erlang vytvářeli.
Doporučuji poslechnout si rozhovor:
http://www.se-radio.net/2008/03/episode-89-joe-armstrong-on-erlang/
a prezentaci:
> S Prologem toho má společného jen málo
Historicky to ma spolecneho hodne:
Erlang started life as a modified prolog.
http://www.erlang.org/faq/academic.html
Ale predrecnika bych uklidnil - Erlang si z Prologu vzal hlavne ty dobre kousky (pattern matching) a zkombinoval je s imperativnim pristupem, takze je daleko prirozenejsi nez Prolog (zadna backtracking se nekona atd.)
Nevim jestli nekde delam chybu, ale dost me zklamala rychlost vysledneho kodu Erlangu OTP 17.1 (i R16).
Trivialni priklad pro vypocet n-teho clenu Fibonacciho rady:
fib(N) -> fib(N,0,1).
fib(0,Res,_) -> Res;
fib(N,Res,Next) when N > 0 -> fib(N-1, Next, Res+Next).
Kompilace s max. optimalizaci:
erlc +native +"{hipe, [o3]}" fib_test.erl
time erl -smp enable -noshell -run fib_test main 1000000
real 0m12.558s
Srovnavaci verze v Pythonu:
def fibIter(n):
if n < 2:
return n
a, b = 1, 1
for num in xrange(2, n):
a, b = b, a+b
return n
time python-2.7 fib_test.py 1000000
real 0m13.260s
U Erlangu jsem ocekaval jsem vyrazne lepsi vysledek nez u dynamickeho a interpretovaneho pythonu. Ma hur optimalizovanou aritmetiku s BigInt ? Nevhodna implementace funkce fib ? Analytickou verzi samozrejme znam, ale srovnavam jablka s jablkama. Naivni rekurzivni neskonci ani za 20 minut.
Napr. nasledujici rekurzivni verze v Haskellu prelozena s ghc -O2 spocita milion clenu za cca 5 s na stejnem stroji.
fib = 1 : 1 : zipWith' (+) (init fib) (tail fib)
where
zipWith' fn (!x:xs) (!y:ys) = fn x y : zipWith' fn xs ys
zipWith' _ _ _ = []
http://erlang.org/pipermail/erlang-questions/2010-October/054183.html
http://erlang.org/pipermail/erlang-questions/2010-October/054191.html
Šlo by na bigint použít toto?
fib(N) -> fib(N,0,1).
fib(0,Res,_) -> Res;
fib(N,Res,Next) when is_number(N) andalso is_number(Res) andalso is_number(Next) andalso N > 0 -> fib(N-1, Next, Res+Next).
Porovnání rychlosti aritmetiky sekvenčního programu v různých jazycích.
http://benchmarksgame.alioth.debian.org/u64/performance.php?test=nbody#about
Erlang je asi dobrý jen v tom, na co ho Ericsson potřeboval - fault tolerance, message passing concurrency a bit syntax. Na telefonních ústřednách výpočty neběží. :/
Ono je to někdy něco za něco. Masivně paralelní systémy bývají běžně i řádově pomalejší než sekvenční systémy. Tedy jen dokud sledujete "výkon na výpočetní uzel". Pokud těch uzlů spustíte stovky, tak pak se to otočí.
Erlang vypadá jako prostředí, kde by režie na paralelní běh mohla mít nižší složitost. Obecně je "celkový výkon" v závislosti na počtu uzlů křivka logaritmická. Bylo by zajímavé vědět, jestli pro nějaké typy úloh dosahuje Erlang výrazného zlepšení (delší úsek linearity apod.)
Erlang nikdy nebyl koncipovany na number crunching a ve vsech materialech se zduraznuje, ze by to nej nemel byt pouzivan, protoze neni efektivni.
> U Erlangu jsem ocekaval jsem vyrazne lepsi vysledek nez u dynamickeho a interpretovaneho pythonu.
Proc? Ten bytekod, do ktereho se pythonni program prelozi, bude nejspis hodne podobny tomu erlangovskemu, tam moc neni co vymyslet...
Tyhle testy na rychlost jednoduchych algoritmu vypovidaji jenom malo o realne pouzitelnosti. Staci si predstavit, ze mam nejaky velky system sestavajici ze spousty modulu, spoustou konkurentni komunikace atd. atd. - v Pythonu dostanu obrovsky moloch se spoustou objektu, miliardou zamku a neustale budu resit nejake pady v produkci, protoze nejaky zamek byl napsany spatne. O paralelizovatelnosti a giant locku ani nemluve.
V Erlangu oproti tomu dostanu jasne definovane aktory s jasnym API, _lokalnimi_ stavy a (typicky) asynchronni komunikaci.
Rozdil mezi jednim a druhym se fakt neda merit rychlosti Fib ;)
Mohl by toto nekdo rozvest? Ja to chapu tak, ze pouziti akumulatoru umozni tail-recursion-elimination. Bez akumulatoru tam je
sum ([N | Tail]) -> N + sum(Tail).
To znamena ze nejdriv musim zavolat sum na Tail a az se vrati tak jeste provest +. Diky tomu to volani nemuze byt primo nahrazeno skokem. Dokazu si ale predstavit, ze kompilator takove pripady pozna a vnitrne je prevede na variantu s akumulatorem.
Dela tedy erlang automaticky takovy prevod? A je nejaky limit na slozitost vyrazu, ktery se bude pocitat po `navratu' z rekurzivniho volani?
PS: Urcite to bude i rychlejsi ale podle me je dulezitejsi vlastnost, ze se behem provadeni cyklu nemusi zvetsovat pamet pro zasobnik.