Scala vs. Java 8.

Kit

Re:Scala vs. Java 8.
« Odpověď #90 kdy: 28. 12. 2016, 12:43:33 »
FP programátoři jsou totiž docela neradi, když jim "pure" kód vyhazuje výjimky.

Ani jeden z uvedených kódů (včetně toho pythoního) pro mne není dost "pure", takže to zřejmě ani nebudu muset řešit.

Však uvidím časem.


wamba

Re:Scala vs. Java 8.
« Odpověď #91 kdy: 28. 12. 2016, 13:56:08 »
FP programátoři jsou totiž docela neradi, když jim "pure" kód vyhazuje výjimky. Takže když v pythonu napíšu:
Kód: [Vybrat]
someJson['key'][3]['nextkey'] + 1Tak to může vyhodit výjimku tak zhruba tak ze 7mi důvodů (cca. 3 různé výjimky v pythonu).
Tak to je jen o přístupu Pythonu. V Perlu
Kód: [Vybrat]
perl6 -e 'my $someJSON; say $someJSON<key>[3]<nextkey> + 1;'vyhodí varovaní taky až to plus a vytiskne to 1.

andy

Re:Scala vs. Java 8.
« Odpověď #92 kdy: 28. 12. 2016, 19:47:45 »
FP programátoři jsou totiž docela neradi, když jim "pure" kód vyhazuje výjimky. Takže když v pythonu napíšu:
Kód: [Vybrat]
someJson['key'][3]['nextkey'] + 1Tak to může vyhodit výjimku tak zhruba tak ze 7mi důvodů (cca. 3 různé výjimky v pythonu).
Tak to je jen o přístupu Pythonu. V Perlu
Kód: [Vybrat]
perl6 -e 'my $someJSON; say $someJSON<key>[3]<nextkey> + 1;'vyhodí varovaní taky až to plus a vytiskne to 1.
Jo, to je přesně o tom přístupu - perl vytiskne 1, python vyhodí výjimku a haskell vrátí Nothing.

Tohle je mimo jiné jedna z odpovědí pro Radka Míčka: napsat stejný kód v haskellu typicky trvá trošku déle (ne o moc), ale když člověk skončí, tak má obvykle kód, který řeší všechny okrajové stavy, zatímco v mnoha jiných jazycích má prototyp...

andy

Re:Scala vs. Java 8.
« Odpověď #93 kdy: 28. 12. 2016, 19:52:30 »
FP programátoři jsou totiž docela neradi, když jim "pure" kód vyhazuje výjimky.

Ani jeden z uvedených kódů (včetně toho pythoního) pro mne není dost "pure", takže to zřejmě ani nebudu muset řešit.

Však uvidím časem.
Jak by to pro tebe vypadalo dost pure? Jen mě to zajímá :)

javaman ()

Re:Scala vs. Java 8.
« Odpověď #94 kdy: 28. 12. 2016, 20:16:32 »
Se chytáš do jeho sítí. On totiž nikde nedefinoval, co pro něj pure znamená  a samozřejmě to bude zase nějaký nesmysl. Bez setterů a komentářů ;D


Kit

Re:Scala vs. Java 8.
« Odpověď #95 kdy: 28. 12. 2016, 20:30:55 »
FP programátoři jsou totiž docela neradi, když jim "pure" kód vyhazuje výjimky.

Ani jeden z uvedených kódů (včetně toho pythoního) pro mne není dost "pure", takže to zřejmě ani nebudu muset řešit.

Však uvidím časem.
Jak by to pro tebe vypadalo dost pure? Jen mě to zajímá :)

S Haskellem teprve začínám, tlačí mě do něj pouze zvědavost. Chci na něm vyzkoušet pár svých sémantických pravidel, která používám v OOP. Nejprve se chci poctivě naučit základy, ke kterým mi pomohou adaptéry na externí datové zdroje, aby to bylo na čem zkoušet a tedy generovat nějaké výsledky. Tyto adaptéry (JSON, XML, HTTP,...) už někdo udělal přede mnou a v tuto chvíli nemám důvod na nich nic měnit. Budu jimi importovat vstupy a exportovat výstupy, což mi jistě umožní některé z prototypů nasadit přímo do ostrého provozu.

Zbývá tedy jádro (resp. jádra) aplikace ve stylu hexagonální architektury s poměrně volnou vazbou na okolní jádra. Jádro bude jeden modul/monáda. Každé z těchto jader bude moci komunikovat pouze se svým sousedem přes funkcionální adaptéry. Mám takové tušení, že lens by mi to místo usnadnění mohl zkomplikovat, proto se jím zatím nechci zabývat.

Nemám tedy pevně stanovený cíl, ale spíš cestu. Slibuji si od toho rozříření obzoru podobně, jak mi to kdysi udělal Lisp.

Radek Miček

Re:Scala vs. Java 8.
« Odpověď #96 kdy: 28. 12. 2016, 21:29:26 »
Člověk je výrazně efektivnější než lidi píšící v jiných jazycích (je to trošku výběrový efekt, ale ten vývoj je fakt výrazně lepší). Ale je pravda, že v Čechách to moc neletí...
Refaktoring v Haskellu je díky silným typům překvapivě záležitost, při které nevzniká mnoho chyb.
Když máte štěstí a nesnažíte se zakódovat (složitější) vlastnosti funkcí do typů (což je vidět na jazycích se závislými typy, kde malá změna může znamenat přepsání celého programu).

A i v Haskellu je kolikrát malá změna velký problém - stačí po funkci, která není v IO chtít něco vyprintit a musíte si pomoci ošklivým trikem nebo změnit i mnoho jiných funkcí, z nichž je tato funkce volána (aby všechny byly v IO).

Citace
FP programátoři jsou totiž docela neradi, když jim "pure" kód vyhazuje výjimky.

Což se ale v Haskellu děje celkem často [] !! 1, head [], 1`div`0 + řada případů, kdy něco vyhazuje Stack overflow, protože někdo někde nepoužil seq (třeba foldl (+) 0 [1..1000000]) nebo kompilátoru něco nedošlo.

andy

Re:Scala vs. Java 8.
« Odpověď #97 kdy: 28. 12. 2016, 22:00:46 »
Když máte štěstí a nesnažíte se zakódovat (složitější) vlastnosti funkcí do typů (což je vidět na jazycích se závislými typy, kde malá změna může znamenat přepsání celého programu).
No haskell zatím dependent typy ještě nemá, ale tak nějak vlastně nerozumím - ano, při refaktoringu člověk občas provede změny, které znamenají, že toho musí přepsat poměrně hodně, ale zatím když se mi to nakonec po přepsání podařilo přeložit, tak to typicky fungovalo...
Citace
A i v Haskellu je kolikrát malá změna velký problém - stačí po funkci, která není v IO chtít něco vyprintit a musíte si pomoci ošklivým trikem nebo změnit i mnoho jiných funkcí, z nichž je tato funkce volána (aby všechny byly v IO).
Ošklivým unsafe trikem si rozhodně nepomáhám, ale já nějak nikdy s tímhle problém neměl. Když něco počítám, zajímá mě výsledek. Spíš je problém při debugování, ale tam se tohle toleruje :)

Citace
FP programátoři jsou totiž docela neradi, když jim "pure" kód vyhazuje výjimky.

Což se ale v Haskellu děje celkem často [] !! 1, head [], 1`div`0 + řada případů, kdy něco vyhazuje Stack overflow, protože někdo někde nepoužil seq (třeba foldl (+) 0 [1..1000000]) nebo kompilátoru něco nedošlo.
[/quote]No a právě pro to lidi, co v haskellu programují  [] !! 1, head [] prakticky nepoužívají. Někdy si lidi do projektů importují vlastní Prelude, kde jsou všechny tyhle funkce vynechané a konstantně se vede diskuze, jestli to nevyhodit i z oficiálního Preludu (jenomže učte pak začátečníky....). Teď jsem se zoufale snažil přivést ghci ke stackoverflow pomocí foldl a nezdařilo se; mimochodem, to mě docela překvapilo - když se to kompiluje se zapnutou optimalizací, tak se (konkrétně tenhle) foldl zfůzuje a funguje to úplně v pohodě...ale jasně tyhle věci se dějí, ale stalo se mi to snad jednou. Takže v podstatě zbývá to dělení nulou.
Jasně, že to není úplně dokonalé - ale přece jen je trošku rozdíl mezi tím Perlovým kódem, který v klidu vydá "nějaký výsledek", pythoním kódem, který aspoň vyhodí výjimky a Haskellovým kódem, kde konstantně překladač upozorňuje, který že krajní případ programátor zapomněl vyhodnotit.... :)

wamba

Re:Scala vs. Java 8.
« Odpověď #98 kdy: 28. 12. 2016, 22:37:22 »
Jasně, že to není úplně dokonalé - ale přece jen je trošku rozdíl mezi tím Perlovým kódem, který v klidu vydá "nějaký výsledek", pythoním kódem, který aspoň vyhodí výjimky a Haskellovým kódem, kde konstantně překladač upozorňuje, který že krajní případ programátor zapomněl vyhodnotit.... :)
Teď to nějak nechápu, co je zázračného na tom, když Haskell vrátí Nothing oproti 1, nebo vyhození výjimky?

gll

Re:Scala vs. Java 8.
« Odpověď #99 kdy: 28. 12. 2016, 23:06:24 »
FP programátoři jsou totiž docela neradi, když jim "pure" kód vyhazuje výjimky. Takže když v pythonu napíšu:
Kód: [Vybrat]
someJson['key'][3]['nextkey'] + 1Tak to může vyhodit výjimku tak zhruba tak ze 7mi důvodů (cca. 3 různé výjimky v pythonu).
Tak to je jen o přístupu Pythonu. V Perlu
Kód: [Vybrat]
perl6 -e 'my $someJSON; say $someJSON<key>[3]<nextkey> + 1;'vyhodí varovaní taky až to plus a vytiskne to 1.
Jo, to je přesně o tom přístupu - perl vytiskne 1, python vyhodí výjimku a haskell vrátí Nothing.

Tohle je mimo jiné jedna z odpovědí pro Radka Míčka: napsat stejný kód v haskellu typicky trvá trošku déle (ne o moc), ale když člověk skončí, tak má obvykle kód, který řeší všechny okrajové stavy, zatímco v mnoha jiných jazycích má prototyp...

V pythonu se dá použít get('key', {}) nebo se dá použít rekurzivní defaultdict jako objecthook

Kód: [Vybrat]
def mydict(d={}):
    return defaultdict(mydict,d)

some_json = json.loads(jsonstring, object_hook=mydict)

Neřeší to překročení indexu u listů.

lopata

Re:Scala vs. Java 8.
« Odpověď #100 kdy: 28. 12. 2016, 23:08:39 »
Teď jsem se zoufale snažil přivést ghci ke stackoverflow pomocí foldl a nezdařilo se; mimochodem, to mě docela překvapilo - když se to kompiluje se zapnutou optimalizací, tak se (konkrétně tenhle) foldl zfůzuje a funguje to úplně v pohodě...

A tohle má být dobrá nebo špatná vlastnost? Protože tenhle kód:
Kód: [Vybrat]
foldl (+) 0 [1..1000000]
S O2 projde, ale bez optimalizací:
Kód: [Vybrat]
Stack space overflow: current size 8388608 bytes.
Musím říct, že tohle mě na Haskellu hodně děsí. Zapnutí optimalizací úplně změní sémantiku vyhodnocování kódu. Pro mě má takový kód undefined behavior a že funguje je jenom náhoda. Co kdy někdo do produkce nasadí kód s vypnutými optimalizacemi? Co když se něco v nové verzi GHC změní a začne to fungovat jinak? Ono se to nemusí projevit hned, ale až tehdy, když se začnou zpracovávat dostatečně velká data, pro malá data může stack stačit.

andy

Re:Scala vs. Java 8.
« Odpověď #101 kdy: 28. 12. 2016, 23:12:55 »
Jasně, že to není úplně dokonalé - ale přece jen je trošku rozdíl mezi tím Perlovým kódem, který v klidu vydá "nějaký výsledek", pythoním kódem, který aspoň vyhodí výjimky a Haskellovým kódem, kde konstantně překladač upozorňuje, který že krajní případ programátor zapomněl vyhodnotit.... :)
Teď to nějak nechápu, co je zázračného na tom, když Haskell vrátí Nothing oproti 1, nebo vyhození výjimky?
Oproti 1 to docela zázračné je, protože to negeneruje "nějaký" výsledek na základě nekorektních vstupních dat. Oproti vyhození výjimky to má tu výhodu, že se to lépe používá. Např. řekněme, že parsuju nějaký seznam:
Kód: [Vybrat]
seznamJsonu = [...]
f :: ByteString -> Maybe Neco -- Naparsuje bytestring, vytáhne z něj Neco
vysledek = traverse f seznamJsonu -- Buď bude Just [Neco, Neco..], nebo Nothing, pokud selhal kterýkoliv parse
vysledek = mapMaybe f seznamJsonu -- Výsledek bude [Neco, Neco] pro ty, ktere se naparsovaly korektne
Ale především - v jiných jazycích se výjimky používají, protože se s tou návratovou hodnotou špatně pracuje. Tohle je typický příklad - tady třeba z Go:
Kód: [Vybrat]
f, err := os.Open("filename.ext")
if err != nil {
    log.Fatal(err)
}
Jenomže v Haskellu se naopak s návratovou hodnotou pracuje dobře:
Kód: [Vybrat]
parsujNekolikJsonu js1 js2 js3 = do
   v1 <- decode js1
   v2 <- decode js2
   v3 <- decode js3
   return (nejakFce v1 + jinaFce v2 * jesteJinaFce v3)
Pokud kterýkoliv z "decode" vrátí Nothing, tak celá funkce vrátí Nothing.

andy

Re:Scala vs. Java 8.
« Odpověď #102 kdy: 28. 12. 2016, 23:48:30 »
A tohle má být dobrá nebo špatná vlastnost? Protože tenhle kód:
Kód: [Vybrat]
foldl (+) 0 [1..1000000]
S O2 projde, ale bez optimalizací:
Kód: [Vybrat]
Stack space overflow: current size 8388608 bytes.
To byla jen poznámka na okraj, protože mě překvapilo, že v základní knihovně se nechává foldl, protože je schopen dobře fůzovat... přišlo mi to zajímavé :)

Citace
Musím říct, že tohle mě na Haskellu hodně děsí. Zapnutí optimalizací úplně změní sémantiku vyhodnocování kódu. Pro mě má takový kód undefined behavior a že funguje je jenom náhoda.
Teď nerozumím - tohle je příklad kódu, u kterého máš v každé učebnici napsané "nedělej to". Přesto má Haskell tak dobrou optimalizaci, že je schopen spoustu tohoto špatně napsaného kódu převést na normálně fungující kód. To je špatně?

Když napíšeš v mnoha jinách jazycích brutálně rekurzivní kód, tak ti to taky časem upadne na stack overflow. Když změníš nastavení velikost stacku, tak se ti to taky bude chovat jinak. Co z toho mám vyvozovat?

Citace
Co kdy někdo do produkce nasadí kód s vypnutými optimalizacemi?
Tak si to taky vyžere. Funkcionální jazyky závisí na tail-call optimalizaci, když ji vypneš, tak ti toho přestane fungovat docela hodně. Mimochodem, stack overflow s vypnutými optimalizacema vyrobíš, pokud vím, i v překladačích C, protože ty to umí taky.
Citace
Co když se něco v nové verzi GHC změní a začne to fungovat jinak? Ono se to nemusí projevit hned, ale až tehdy, když se začnou zpracovávat dostatečně velká data, pro malá data může stack stačit.
Takže se Haskell nemá snažit tyhle věci optimalizovat? Navíc pokud děláš tyhle výpočty, tak na to jsou direktivy "Strict" a "StrictData", které tě těchto problémů v podstatě zbaví.

Že nemáš používat foldl je napsané prakticky v každém učebnici Haskellu. Šlo by dávat příklady toho, jak je ten jazyk špatný, z jiné kapitoly než z té, jejíž téma je "jak se vykonává haskellový kód a na co si dát pozor"?

lopata

Re:Scala vs. Java 8.
« Odpověď #103 kdy: 29. 12. 2016, 00:26:29 »
Teď nerozumím - tohle je příklad kódu, u kterého máš v každé učebnici napsané "nedělej to". Přesto má Haskell tak dobrou optimalizaci, že je schopen spoustu tohoto špatně napsaného kódu převést na normálně fungující kód. To je špatně?
Dobře, tak jiný kód:
Kód: [Vybrat]
fac x = fac' x 1 where
    fac' 1 y = y
    fac' x y = fac' (x-1) (x*y)

main = print (fac(1000000))
Tohle bez optimalizací spadne na stack overflow, protože Haskell neudělá tail-recursive optimalizaci. Takže jinými slovy Haskell mě nutí, abych veškerý kód používal za všech okolností s O2 optimalizací, jinak není nic zaručeno.

Když napíšeš v mnoha jinách jazycích brutálně rekurzivní kód, tak ti to taky časem upadne na stack overflow. Když změníš nastavení velikost stacku, tak se ti to taky bude chovat jinak. Co z toho mám vyvozovat?
To je právě ono, v imperativních jazycích žádný brutálně rekurzivní kód nenapíšeš, proč bys to dělal? Napíšeš cyklus. Ve funcionálních jazycích je rekurze naprosto typický design pattern, jinak se v tom v podstatě programovat nedá. Jenže v Haskellu to bez O2 nefunguje.

Citace
Co kdy někdo do produkce nasadí kód s vypnutými optimalizacemi?
Tak si to taky vyžere. Funkcionální jazyky závisí na tail-call optimalizaci, když ji vypneš, tak ti toho přestane fungovat docela hodně.
Což je dost hrozné, proč se to nedá používat normálně i s vypnutými optimalizacemi? Nebo jinak, proč vůbec jdou ty optimalizace vypnout, když bez nich pořádně nic nefunguje?

Mimochodem, stack overflow s vypnutými optimalizacema vyrobíš, pokud vím, i v překladačích C, protože ty to umí taky.
Vyrobíš, ale musíš se hodně snažit, aby se ti to povedlo, typicky to nenastává. Haskell se s vypnutými optimalizacemi prakticky nedá používat.

wamba

Re:Scala vs. Java 8.
« Odpověď #104 kdy: 29. 12. 2016, 00:41:38 »
Oproti 1 to docela zázračné je, protože to negeneruje "nějaký" výsledek na základě nekorektních vstupních dat. Oproti vyhození výjimky to má tu výhodu, že se to lépe používá.
Proč nekorektní? Když se nedefinovaná hodnota bere jako 0, tak je to sice nezvyklé, ale ne nekorektní. Stejně tak se někomu může zdát nekorektní agresivní chování Nothink. Někdy se může hodit to jindy ono.
Tohle
Kód: [Vybrat]
perl6  -e 'for lines() { say join ";\t", ++$, $_, ++(%){ .split(":")[*-1] } }' /etc/passwd vepředu očísluje řádky a na konci je očísluje zvlášť pro každý shell. Kdybych výše zmíněného chování nevyužil, tak bych pro každý klíč (shell) musel testovat jestli už je definován.

Jak se chová v Haskelu např. "+" v následujícím případě?
Kód: [Vybrat]
perl6 -e 'say "12" + 1' #13