Zobrazit příspěvky

Tato sekce Vám umožňuje zobrazit všechny příspěvky tohoto uživatele. Prosím uvědomte si, že můžete vidět příspěvky pouze z oblastí Vám přístupných.


Příspěvky - Mirek Prýmek

Stran: 1 ... 180 181 [182] 183 184 ... 618
2716
Vývoj / Re:Dědičnost dnes
« kdy: 28. 01. 2017, 16:26:46 »
Tak jsem to pročetl... Je-li pan Armstrong spoluautorem Erlangu, je zarážející, že podstatu OOP naprosto, ale NAPROSTO nepochopil:
Ve tvrzeních o Armstrongovi bych byl opatrnější. Když člověk trochu zná výsledky jeho práce, vidí na vlastní oči, jak velice dobře různé problémy Erlangovský tým vyřešil. Člověk občas až žasne, jak u spousty problému zvolili řešení, které prozíravě předchází problémům, které se (ne)projeví až o několik tahů později. Působí to na mě jako přesný opak třeba javascriptového světa, kde každý krok typicky jeden problém vyřeší a deset nových způsobí :)

Objection 1: OOP oproti FP "data" a "funkce" spojuje z jednoduchého důvodu, a to, že data bez funkcí jsou k ničemu stejně tak jako funkce bez dat, přičemž funkce jsou vytvořeny pro daná data (to nevylučuje práci s obecnými daty jako v FP!). Myšlenka nutnosti nespojovat funkce a data jen z důvodu, že se jedná o jiné kategorie, je neopodstatněná (to ale neznamená, že to nejde).
Tam jde myslím spíš o to, že OOP svazuje konkrétní fce s konkrétními ("svými") daty a tím komplikuje (záměrně - a podle některých chybně) přístup k datům jinými fcemi.

Stupidní příklad: fce List.reverse(list) může fungovat nad listem čehokoli, protože o položkách nic nepředpokládá. Vesele teda jednou jedinou funkcí otáčím listy zákazníků, faktur i planet sluneční soustavy. Když chci totéž udělat u OOP, tak mi tenhle jeden problém exploduje do tisíce dalších: asi teda chci nějaké rozhraní IReversable, nebo chci nějak data zpřístupnit? Nebo pro každý objekt úplně nezávisle napíšu tutéž fci o.reverse()? Co je správně? Co je antipattern? Co porušuje zapouzdření? Neměl by objekt PlanetList dědit z List? No jo, ale já potřebuju, aby dědil z PlanetsOfSolarSystem. Co s tím? Vícenásobná dědičnost? Ale ne, to je fuj. atd.atd.atd. Armstrong tvrdí (nemusíš s ním souhlasit, ale myslím, že to nemůžeš jenom tak šmahem odbýt), že kdybys ty data nesvázal s konkrétními, předem danými funkcemi, měl bys míň problémů.

Objection 2: Různé třídy (typy; či prototypy) pro různé časové údaje se používají v implementacích OOP naprosto běžně - tento bod je nadbytečný.
Ten bod je spíš špatně vysvětlený. Nejde tam imho o to, že máš víc typů, ale že ty typy jsou "ubiquitous and data structures representing times can be manipulated by any function in the system" a že "There are no associated methods.". Čili to souvisí s předchozím a následujícím bodem. Např. na některé typy zachycující čas můžu v FP aplikovat List.reverse, když mi to bude dávat smysl. V OOP by nikdo nepředpokládal, že to budu chtít udělat, takže by neimplementoval IReversable, takže bych musel z Time dědit do svého MyReversableTime, který o IReversable rozšířím, jenže pak ho nemůžu serializovat stejně jako Time, protože na druhé straně MyReversableTime nemám a navíc ... (opět exploze pseudoproblémů)

Objection 3: Všudypřítomné "typy" se realizují třídami či prototypy. Poslední věta fabuluje cosi o nutnosti dědění.
Opět je tam klíčové to "ubiquitous". Prostě na jednom místě mám definováno, jakou strukturu mají data pojmenovaná "List" a používám to všude. Nepotřebuju řešit pseudoproblémy typu "Všechny objekty musí dědit z Object".

Objection 4: Objekty mají skryté stavy, ale nedávno mi tu pan Prýmek vysvětlil na Elixíru, že FP je má taky, akorát je jinak ukládá. Kde je potom rozdíl?
Říká tam, že stav nechceme, protože je s ním opruz, ale nějakým způsobem potřebujeme řešit, protože práce se stavem je cílem programování v reálném světě. Takže stav nějak ošetřit potřebujeme, máme na to několik možností. A Armstrong říká (opět s ním nemusíš souhlasit), že způsob práce se stavem, který zvolilo OOP, je nejhorší možný z dostupných.

---
Btw, velmi doporučuji se kouknout na video, kde Armstrong s Kayem diskutují. Neřekl bych, že by si nějak zvlášť vjížděli do vlasů. Spíš naopak - vypadá to, že oba dva se shodují na tom, že to, co se z OOP stalo, stojí za starou belu ;)

[EDIT: sorry, nějak jsem si spletl Kaye s Johnsonem ;) ]

https://www.infoq.com/interviews/johnson-armstrong-oop

Ještě je na YT jedno video s nima oběma, to jsem ale zatím neviděl.

2717
Vývoj / Re:Dědičnost dnes
« kdy: 28. 01. 2017, 15:41:09 »
Data možná, ale hodnota proměnné lze změnit. Narozdíl od Erlangu.

Kód: [Vybrat]
iex(1)> fn -> a=1; a=2; a end.()  
2
Opakuju: nemá  to vůbec žádné důsledky, je to jenom syntaktický cukr. Neplyne z toho, že by byl Elixir "míň striktní".

To elixirovské
Kód: [Vybrat]
a = 1
a = 2
f(a)
se prostě jakoby do Erlangu převede jako:
Kód: [Vybrat]
a1 = 1
a2 = 2
f(a2)

2718
Vývoj / Re:Dědičnost dnes
« kdy: 28. 01. 2017, 15:35:48 »
Třetí věc je, že co se týče hrubého výkonu, je Erlang (a tímpádem i Elixir) poměrně dost pomalý - v testech typu https://benchmarksgame.alioth.debian.org/ nemá šanci.
Taky k tomu ještě doupřesnění, ať nevzniká mylnej dojem: z tohodle nijak neplyne nepoužitelnost pro praktické problémy nebo špatný výkon v reálných aplikacích. Zatímco třeba Python nebo Ruby jsou prostě pomalý a nemají to čím vyvážit, takže jediný způsob, jak s nima dělat něco použitelnýho, je začít využívat hrubé hacky jako nativní céčkové knihovny nebo kdovíjaké obcházení GILu, Erlang tu základní "hrubou" pomalost víc než vyvažuje právě tou parádní paralelizovatelností a ještě jinými drobnostmi, jako třeba elegantním garbage collectorem (díky nepřekročitelné immutabilitě), takže celkový výkon bývá velice příjemný.

Doporučuju třeba zkusit zagooglit "phoenix benchmark" - phoenix je Elixirovský webový framework s parádním výkonem.

2719
Vývoj / Re:Dědičnost dnes
« kdy: 28. 01. 2017, 15:19:49 »
To zní dost dobře. Takže proč se nepoužívá víc? Znám třeba RabbitMQ, který je hodně populární. Ale třeba ActiveMQ umí cca to stejné a i stejně rychle. Takže v Erlangu by byl vývoj rychlejší? Je lépe udržovatelný? Nebo co je ta hlavní výhoda a zároveň proč se nepoužívá více?
Pro nic z toho nemám žádná tvrdá data, takže těžko říct, můžu posloužit jenom mými subjektivními dojmy...

Subjektivně má Elixir trochu zvlněnou křivku učení - ty základy (syntaxe, moduly, funkce, protokoly) dá programátor v jiném jazyce tak za den, dva. Potom ale musí projít velkým mind-twistem, aby pochopil, jak se z nezávislých procesů, komunikujících jenom pomocí zpráv, stavějí větší systémy. U programátora bez zkušeností třeba s tím SmallTalkem nebo ObjC může tohle trvat docela dlouho. A pak nastává období, než ty patterny začne psát úplně automaticky. Teprve až projde tímhle, začíná být v Elixiru opravdu produktivní. Tohle by mohlo být spoustě lidem nepříjemný.

Druhá věc je, že se o Elixiru prostě neví (proto ho tady propaguju, protože podle mě stojí za pozornost pro každého programátora jako občerstvení a nakouknutí, jak se dají věci řešit i jinak...). O Erlangu se ví trochu víc, ale Erlang má dost nepříjemnou syntaxi, která asi hodně lidí odradí.

Třetí věc je, že co se týče hrubého výkonu, je Erlang (a tímpádem i Elixir) poměrně dost pomalý - v testech typu https://benchmarksgame.alioth.debian.org/ nemá šanci. To je tím, že byl původně navržený pro konkrétní problém (programování telefonních ústředen Ericsson) s návrhovými kritérii: 1. obrovský důraz na spolehlivost 2. masivní paralelizace 3. distribuovanost 4. možnost updatů za běhu (souvisí s 1). Rychlost byla požadovaná jenom na úrovni "soft-realtime". Hrubá rychlost number crunching nebyla cílem.

Čtvrtá věc je, že Erlang se nikdy nevezl na módní vlně, spíš přesně naopak - vznikal v době, kdy největší buzzword byl OOP a přitom šel do velké míry proti němu (v té jeho tehdejší módní podobě). Dneska už je to trochu jinak, do módy se dostává právě spíš FP a paralelismus, takže Elixir imho má celkem šanci, ale nějaký velký, masový úspěch bych mu nepredikoval, na to je málo easy, cool. Masový úspěch bych čekal spíš u Go.

Jinak, moje subjektivní zkušenost je taková, že jakmile jsem si na koncepty Elixiru zvykl, píše se mi v něm strašně příjemně, přirozeně - nemusím si strašlivě trápit hlavu a prostě si jenom tak hezky píšu a ono to funguje ;) Tím je to pro mě výrazně příjemnější než třeba to OOP, kde se pořád dokola řeší nějaké filosoficko-návrhové prkotiny typu co má být private, co dědit z čeho, co je "pravé" OOP, co je antipattern atd. atd. nebaví mě to, nechtěl bych se do tohodle světa vracet :)

Jinak objektivněji, Erlang má suprově navrženou knihovnu OTP, která umožňuje velice snadno dosáhnout věcí, které v jiných jazycích sice jdou třeba taky, ale je to hrozně náročný a spousta lidí si na tom vyláme zuby. Typicky ta distribuovanost a updaty za provozu. Proto si z OTP vzal příklad Akka framework a třeba takový Flink může díky němu poskytnout krásnou, jednoduchou a rock-solid distribuovanost hned ze startu - rozdíl např. oproti klasickým databázím, kde se podobné věci řeší desetiletí a pořád to tak nějak limitovaně funguje, ale sem tam jenom když je pátek odpoledne, bezvětří a nezapisuješ moc často ;)

2720
Vývoj / Re:Dědičnost dnes
« kdy: 28. 01. 2017, 14:02:35 »
Neznam Elixir, ale myslim, ze nebyl ciste FP, takze bych se nedivil, kdyby tam byly mutable veci podobne jako ve Scale.
Ne, tak jako ve Scale ne, ani trochu.

Elixir je taková "nadstavba" nad Erlangem, tady z těch základních věcí tam platí všechno, co v Erlangu:

1. data jsou naprosto striktně immutable, nejde je měnit vůbec nijak (neexistuje ani žádný hack/pragma/meta/výjimka, která by to umožnila)

2. funkce můžou mít vedlejší efekty => není garantovaná referenční transparentnost

3. primárním cílem Erlangu/Elixiru není funkcionální programování, ale "concurrent programming". FP je tam jenom do té míry, do které dává smysl jako podvozek pro CP. Proto Elixir ani Erlang nejsou "čisté" funkcionální jazyky, spíš pragmatické. Ale zase to není takový ten kočkopes jako Scala, kde si můžu vybrat, že v téhle části kódu použiju X a v jiné Y, tady budu mutabilní a tady ne. To v Elixiru není.

4. základním stavebním blokem Erlangu jsou procesy, které komunikují pomocí zpráv a nemůžou sdílet stav jinak než přes databázi (protože bod 1).

5. Erlang a (trochu míň) Elixir mají kořeny v Prologu,  ne v FP. Proto je tam z FP jenom to, co pragmaticky dávalo smysl pro celek toho jazyka (a vybrali to velmi dobře - ten jazyk a celý ekosystém je neuvěřitelně dobře navržený, pořád mě to nepřestává překvapovat, jak dobře to tenkrát udělali).

2721
Vývoj / Re:Dědičnost dnes
« kdy: 28. 01. 2017, 13:29:50 »
Možná mi něco nedocvaklo, ale blokování asynchronního volání (resp. čekání) má taky režii, potřebuju třeba semafor nebo tak něco, ne?
V implementaci jo. Ale v jazyce můžu mít třeba jenom to zmíněné
Kód: [Vybrat]
receive do
  :message_i_am_waiting_for -> :ok
end
...což mi přijde parádně čitelné - na první pohled vidím "tady čekám na zprávu".

2722
Vývoj / Re:Dědičnost dnes
« kdy: 28. 01. 2017, 13:26:29 »
Erlang je v některých ohledech přísnější než Elixir. Elixir má narozdíl od Erlangu mutable proměnné. Což považuji za výhodu.
Ne! To je jenom syntaktický cukr, aby člověk nemusel psát
Kód: [Vybrat]
v = 1
v1 = v+2
v2 = v1 + 3
...což strašně komplikuje přepisování kódu.

Elixir a Erlang se v tomhle liší jenom syntaxí, ale podvozek je úplně stejný.

Viz http://stackoverflow.com/a/30000838/3150343

2723
Vývoj / Re:Dědičnost dnes
« kdy: 28. 01. 2017, 13:19:46 »
I když pokud má jazyk/runtime třeba channels, tak to vyjde nastejno i v opačném směru, asynchronizační funkce vrátí "channel rettype" a hodnotu si pak přečtu asynchronně, ale kód vlastně bude vypadat synchronně.
Jo, channel tam vlastně sehraje úlohu toho "asynchronizačního bufferu". Pořád je to ale to "něco navíc", co musím někde vytvořit, má to (aspoň teoreticky) nějakou režii, nějak to komplikuje kód. Přijde mi daleko přímočařejší kód, který když nechci, aby blokoval, tak nedělám nic, když chci, aby blokoval, tak prostě čekám na místě, dokud nedojde k události. Vytvářet thread/rutinu/channel kvůli jednomu volání je prostě (pocitově) pro mě míň estetické ;)

...ale to jsme se dostali do zbytečných detailů, myslím, že si rozumíme a nejsme v žádném sporu :)

2724
Vývoj / Re:Dědičnost dnes
« kdy: 28. 01. 2017, 13:14:17 »
Nevim, mě na tom nic složitého nepřijde a dá se to snadno pochopit i bez znalostí tuny teorie. IMHO to spousta lidí používá v praxi i mimo FP aniž by znali pojem monáda (což bude asi největší problém, že neznají pojem a ne myšlenku). Např. optional template v boostu.
Už jsme se tady o tom bavili spoustukrát, tak to nechci rozpitvávat, ale jednu poznámku si dovolím (opakovaně): koncept monády je obecný koncept, který má mnoho instancí. "Chápat monády" znamená chápat ten obecný koncept, chápat, že jeho jednotlivé instance mají nějaké společné vlastnosti, že je to z nějakého pohledu totéž. Např. že list, maybe a future mají stejný princip. A to je úplně něco jiného než umět používat list nebo future.

To, cos řekl, je úplně to samé, jako bys řekl:
Citace
Spousta lidí používá v praxi sčítání aniž by znali pojem monoid.
...jistě. Protože chápat sčítání a chápad monoid jsou dvě dost rozdílné věci.

Moc se mi líbilo, když Evan Czaplicki (autor jazyka Elm) říkal (volně):
Citace
- Nemluvme o monádách! Vůbec ten pojem nepoužívejme, mluvme o x,y,z...
- Ale jak pak pojmenujeme jejich společné vlastnosti?
- Jejich společné vlastnosti samozřejmě jsou "monáda", my o nich ale nepotřebujeme mluvit.


2725
Vývoj / Re:Dědičnost dnes
« kdy: 28. 01. 2017, 12:58:32 »
Jen jsem upozornil, že to nemusí být vlákno, tedy místo start_thread je obecně start_routine (viz. obecněji concurrency vs. parallelism).
Souhlas, dík za doplnění. Nic to ale nemění na tom, že:
Proto je defaultní asynchronnost lepší, protože asynchronní je prostě asynchronní a pokud chci blokovat, tak blokuju přímo ve vlákně volajícího, něpotřebuju nic "navíc".

2726
Vývoj / Re:Dědičnost dnes
« kdy: 28. 01. 2017, 12:52:36 »
To není tak úplně pravda, stačí jen vytvořit/přepnout kontext, podobně jako v Go, kde klidně může běžet plně asynchronní program na jednom vlákně. V C by se to dělalo typicky přes ucontext. Pak se dá snadno napsat kupříkladu něco jako node.js bez callbacků.
Myslel jsem prostředky toho jazyka samotného. Pokud mám fci, která blokuje, třeba http_get_content(uri), tak programátorskými prostředky (uvnitř jazyka) z ní asynchronní neudělám jinak než (pseudokód):
Kód: [Vybrat]
start_thread(fun(){
  content = http_get_content(uri)
  do_something_with(content)
})
this_is_not_blocked(x,y,z)

Maximálně bych mohl mít v jazyce nějakou spešl konstrukci, která se vnitřně přeloží nějak speciálně, třeba samostatná vlákna runtime simuluje v rámci jednoho vlákna, ale to je z louže pod okap... Ta situace s asynchronností jako defaultem mi prostě přijde lepší (YMMV).

2727
Vývoj / Re:Dědičnost dnes
« kdy: 28. 01. 2017, 12:44:28 »
Tail-call je o optimizaci návratu po návratu. V uvedeném příkladu zavolání loop(něco) se odnikud nevrací, naopak buďto je to rekurze a zásobník roste, nebo je to skok a stejně je třeba vytvořit nový kontext, ale starý je zahoditelný.
Ano, starý kontext se zahazuje v případě, že dojde ke změně stavu. Tím se to liší od těch monád, kde jde spíš o f(g(h(x))).

2728
Vývoj / Re:Dědičnost dnes
« kdy: 28. 01. 2017, 12:33:36 »
Tady jsme si spíš nerozuměli, předpokládal jsem, že se porovnává funkce z imperativních jazyků (tj. v podstatě procedura) s objektovým posíláním. Funkcionální funkci (tj. v podstatě matematickou funkci) jsem na mysli neměl.
Ok.

To vypadá dobře. I když implementovat asynchronní v synchronním jde tady.
Jde, ale je to míň praktické - musím pro každé volání rezervovat thread/process. Proto je defaultní asynchronnost lepší, protože asynchronní je prostě asynchronní a pokud chci blokovat, tak blokuju přímo ve vlákně volajícího, něpotřebuju nic "navíc".

3. odeslání zprávy nemusí nic "vracet" nebo může "vracet" víc hodnot postupně
...
To už je věcí implementace na druhé straně, to bych tu nerozebíral. Ale vypadá to zajímavě.
Chtěl jsem tím říct, že (asynchronní) posílání zpráv je "obecnější" než volání funkce - v takovém spíš sémantickém než technickém smyslu, protože samozřejmě funkci taky můžu předat callback, který pak bude volat znovu a znovu...


Monády mi stačila, jen jsem je nestihl prostudovat.
Monády jsou v principu celkem jednoduché, ale bývá problém je vysvětlit/pochopit, proto jsem dal příklad, který je myslím každému programátorovi jasný na první pohled.

Každopádně důsledkem je, že vnitřně je modul sice immutable, ale navenek (a to mě v interakci s ostatními zajímá) pochopitelně mutable.
Tady nebezpečně motáš pojmy. Mutabilita se týká dat. Co je "mutabilita modulu", to bysme si museli nějak zadefinovat, jinak to bude plácání o koze a o voze :)

Tzn. tvrzení, že v FP je vše immutable, asi nebude pravdivé. Dále předpokládám, že jsou hodnoty při volání funkce či posílání zprávy předávány odkazem, jinak by celé toto čarování nemělo smysl.
V různých jazycích je to různě. V tom Elixiru, ve kterém příklad byl, platí, že jakmile mám jednou nějaká data, tak je už nikdy nemůžu změnit. Čili tam vůbec nedává smysl mluvit o volání odkazem nebo hodnotou - je to úplně to samé, je mi úplně jedno, jak je to implementované, protože třeba asoc. pole {'a' => 1} bude už navždy mít jenom jeden klíč, nikdo tam nijak nemůže přidat druhý. Čili to pole můžu úplně klidně předávat kamkoli, do kolika vláken chci a nemusím se bát, že by mi ho nějaké jiné vlákno neočekávaně změnilo pod rukama. Pokud někdo chce do pole přidat další klíč, vznikne mu nové pole, které s tím starým nemá nic společného (a navíc protože původní už nikdo nemůže změnit, můžou ty dvě pole úplně klidně a bezpečně sdílet data - ale to už je otázka implementace, která mě jako uživatele jazyka nezajímá).

Nicméně Elixir (a jeho "podvozek" Erlang) negarantují to, že když dvakrát zavolám tu stejnou funkci se stejnými parametry, dostanu stajný výsledek. Čili k tomu stavu můžu přistupovat přes funkci (která obalí posílání zpráv) a dostanu pokaždé stav, který je aktuální v daném okamžiku.

Ve víc striktních jazycích (Haskell, Elm, ...) tohle neplatí. Tam ta garance je ještě tvrdší než v Elixiru. Proto jsem říkal, že v různých je zycích je "míra imutability" (a tím i míra platných garancí) různá.

2729
Vývoj / Re:Dědičnost dnes
« kdy: 24. 01. 2017, 20:37:09 »
K tomu StateHolder ještě praktická ukázka použití, pokud to někomu pomůže...

Kód: [Vybrat]
iex(2)> sh = StateHolder.start_link
#PID<0.107.0>

iex(3)> send(sh,{:get_state,self()})
{:get_state, #PID<0.81.0>}        <--------- funkce send/2 vrací to, co poslala, to nás nezajímá

iex(4)> flush           <----------- tímhle vyberu zprávy pro aktuální proces (tj. "tazatele", ne sh)
{:state_is, 0}
:ok

iex(5)> send(sh,{:add,10})
stav se meni z 0 na 10      <----------- tohle vypsal StateHolder
{:add, 10}

iex(6)> send(sh,{:add,10})
stav se meni z 10 na 20
{:add, 10}

iex(7)> send(sh,{:get_state,self()})
{:get_state, #PID<0.81.0>}

iex(8)> flush
{:state_is, 20}
:ok

2730
Vývoj / Re:Dědičnost dnes
« kdy: 24. 01. 2017, 20:26:09 »
Zprávy mají s funkcemi společnou jedinou věc, a to, že synchronně vracejí odpověď. Tím jejich podobnost končí.
To je minimálně zavádějící tvrzení.

1. funkce jsou statické, zprávy jsou akce

Pokud se "funkcí" myslí to, co funkce znamená v (čistém) FP, tak funkce není nic jiného než zkratka pro nějaký dlouhý výraz - kdekoliv dám funkci, tam bych mohl dát ten dlouhý výraz (referenční transparentnost), nic víc. Celý program v čistém FP je vlastně striktně vzato sémanticky úplně statický - není to popis činnosti (co se má udělat kdy a jak), je to úplně statický popis relací mezi daty. Např. fce sqr(x) neříká "vem x a udělej s ním něco", říká, že čísla 3 a 9 jsou v relaci sqr. Protože samozřejmě chceme programovat nějakou činnost, má FP jazyk nějaký runtime, který tu statickou strukturu vezme a podle ní něco dělá. V samotném jazyce ale nic "dělat" nejde. Není jak.

2. zprávy nemusí být synchronní

...a dokonce je lepší, když defaultně nejsou, protože sesynchronizovat asynchronní události je v dobře navrženém jazyce triviální (kód v jazyce Elixir):
Kód: [Vybrat]
# synchronni fce - vrati :ok nebo :timeout
def ping_sync do
  # poslu zpravu agentovi
  send(agent,{self(),:ping})
  # cekam na odpoved nebo timeout
  receive do
    :pong -> :ok
  after 5000 -> :timeout
  end
end

3. odeslání zprávy nemusí nic "vracet" nebo může "vracet" víc hodnot postupně

Např. můžu actoru poslat zprávu
Kód: [Vybrat]
{self(),:subscribe_seconds}
a on mi od té doby bude každou sekundu posílat zprávy typu
Kód: [Vybrat]
{:seconds_now,1485285333}
Zprávy pochopitelně chodí úplně nezávisle na tom, co zrovna příjemce dělá (tj. musí tam být nějaký mailbox). A je čistě na příjemci, jestli je zahodí, nebo si hodnotu aktuálního času napíše na čelo lihovou fixkou :)

...prostě asynchronní zprávy kombinované se vzájemně neblokovanými aktory/agenty mají obrovské možnosti, které se dost těžko představují, dokud si v tom člověk fakt prakticky nezkusí něco napsat.

Jak se modelují změny stavů pomocí immutable, jsem se stále nedozvěděl, ale to neznamená, že to nejde, třeba jo.
Immutable je immutable, takže pokud si pod "změnou stavu" představuješ změnu in situ, tak nijak. Jinak to ale může vypadat třeba takhle (jeden příklad z jiného světa, když odpověď "monády" ti nestačila):

Kód: [Vybrat]
# zjednodušený ilustrační příklad, v reálu by to vypadalo trochu jinak
defmodule StateHolder do
  # tahle funkce spustí agenta držícího stav
  def start_link() do
    # spustí funkci loop s parametry [0] v novém vlákně
    spawn_link(fn -> loop(0) end)
  end

  def loop(state) do
    receive do
      {:add,k} ->
        new_state = state + k
        IO.puts "stav se meni z #{state} na #{new_state}"
        loop(new_state)
      {:get_state,pid} ->
        send(pid,{:state_is,state})
        loop(state)
    end
  end

end

Stran: 1 ... 180 181 [182] 183 184 ... 618