Rychlost Haskell vs. C++

Re:Rychlost Haskell vs. C++
« Odpověď #75 kdy: 26. 08. 2018, 14:08:00 »
No vidíš a dlouhou dobu se v produkci používaly.... Co třeba Java s nullpointerexception? Taky se dlouho používala - a používá.
Co je nebezpečného na tom, že Java předvídatelně vyhodí výjimku při dereferencování null pointeru ? C umí akorát SIGSEGV při přístupu na určitý rozsah adres a asi právě proto adresový prostor nezačíná na nule, ale o několik megabytů výše. V případě hodně dlouhého pole začínajícího na nule se to odchytit nemusí. Problém pointerů a v C ale jinde. Snadno se poškodí nesouvisející paměť, v horším případě zásobník a chyba se nemusí projevit ihned na místě chyby v kódu, ale může se projevit se zpožděním naprosto nepředvídatelně a tudíž neodhalitelně.

Maně si vybavuju, že právě že na nule by neměl začínat žádný paměťový segment namapovaný do adresového prostoru procesu a proto přístup k adrese 0 (která je součástí takové "nenamapované" stránky) způsobí ten segfault.
Jinak samozřejmě když pointer nastavím na jakoukoli hodnotu v existujícím prostoru adres, tak se ten segfault vyhodit nemusí a pak už záleží jen na tom, kam ten pointer ukazuje.
(podařilo se mi to dohledat: https://en.wikipedia.org/wiki/Page_fault#Invalid)

PS: Ale jinak samozřejmě souhlasím s pointou Tvé poznámky.


andy

Re:Rychlost Haskell vs. C++
« Odpověď #76 kdy: 26. 08. 2018, 18:07:25 »
Andy, pořád jsi nepochopil, jaká je strict vyhodnocení v Haskellu prasárna. Nevadí, zkusím to znovu. Změnit způsob vykonávání kódu a změnit sémantiku existujícího kódu jsou totiž dost rozdílné věci. Když píšeš třídu v C++, nemusíš přemýšlet o tom, jestli bude vytvořená na heapu nebo na stacku, bude fungovat v obou případech. Neexistuje žádné pragma stack ani pragma heap, které by měnilo sémantiku kódu ve třídě, podle toho, jestli je vytvořená na stacku nebo heapu. Pragma strict v Haskellu to ale dělá, kód který funguje bez pragma strict nemusí fungovat s ním a naopak.
volatile? V kombinaci s -O0 a -O2? To ti v multithreadovaným programu sakra změní sémantiku kódu.

Citace
Úlpně to mení sémantiku kódu, nikoliv takové detaily, kde leží data, jestli na stacku nebo na heapu.
Úplně..? Jako že ti ta část kódu vrátí JINÝ výsledek? Fakt? Tak to by mě zajímalo, protože pokud vím, tak ta změna je maximálně v tom smyslu, že za určitých dost specifických okolností místo bottom vrátí smysluplný výsledek (fusion) nebo naopak místo výsledku to dá bottom. Tomu říkáš "úplně změní sémantiku kódu"?

andy

Re:Rychlost Haskell vs. C++
« Odpověď #77 kdy: 26. 08. 2018, 18:28:35 »
Já tě stejně nechápu. Označení parametru/části recordu jako strikt samozřejmě mění sémantiku, ale je to asi tak na té úrovni, jako když v C++ použiješ "&". To taky mění sémantiku. A taky se to používá pro rychlost. Strict/StrictData vzniklo, protože pro některé typy úloh je lepší mít všechno strict. Když člověk píše nějaký modul, který v podstatě jenom něco počítá, tak typicky chce všechno strict. Tak tam přidali tuhle pragmu, aby nemusel před každý parametr psát vykřičník. Proto jsou taky tyhle direktivy 2 - StrictData a Strict, přičemž typicky StrictData je bezpečná a Strict poněkud méně. Stejně maximálně tak nějaký kód vrátí bottom...

Pokud ti to připadá nebezpečné, tak ty direktivy prostě nepoužívej a piš si ke každému parametru vykřičník. V čem je problém?
BTW, kompilátory, které pracují s floating point kódem, mají takové milé direktivy typu "-ffast-math" apod., které také mění sémantiku floating point kódu...

andy

Re:Rychlost Haskell vs. C++
« Odpověď #78 kdy: 26. 08. 2018, 18:36:50 »
No vidíš a dlouhou dobu se v produkci používaly.... Co třeba Java s nullpointerexception? Taky se dlouho používala - a používá.
Co je nebezpečného na tom, že Java předvídatelně vyhodí výjimku při dereferencování null pointeru ? C umí akorát SIGSEGV při přístupu na určitý rozsah adres a asi právě proto adresový prostor nezačíná na nule, ale o několik megabytů výše. V případě hodně dlouhého pole začínajícího na nule se to odchytit nemusí. Problém pointerů a v C ale jinde. Snadno se poškodí nesouvisející paměť, v horším případě zásobník a chyba se nemusí projevit ihned na místě chyby v kódu, ale může se projevit se zpožděním naprosto nepředvídatelně a tudíž neodhalitelně.
To, že vůbec něco jako null pointer exception existuje (resp. že na to je poměrně obvykle i při slušném psaní kódu narazit). V Javě jakýkoliv datový typ obsahuje null. V Haskellu ne (obsahuje bottom, ale to je trošku jiná kategorie - ale i to se mnohým nelíbí a chtěli by totality checking). Ten rozdíl je v tom, že pokud člověk programuje v Haskellu (a nepoužívá prasácké funkce), tak žádná null pointer exception nenastane. Obdoba v haskellu by byl nějaký neošetřený pattern match, ale na to kompiler kromě nějakých extrémních situací upozorní. A právě v Javě s tímhle bojovali, takže od toho jsou tam dneska anotace @Nullable, @NonNull, a nebo to třeba pak řeší i Kotlin, kde už jde specifikovat, jestli typ může obsahovat null nebo ne - opět vliv jazyků typu Haskell.

Re:Rychlost Haskell vs. C++
« Odpověď #79 kdy: 26. 08. 2018, 19:43:06 »
A právě v Javě s tímhle bojovali, takže od toho jsou tam dneska anotace @Nullable, @NonNull, a nebo to třeba pak řeší i Kotlin, kde už jde specifikovat, jestli typ může obsahovat null nebo ne - opět vliv jazyků typu Haskell.
Jenom doplním, že anotace jako @Nullable nebo @NotNull pocházejí z externích knihoven, samotná Java to od verze 8 řeší třídou Optional. Jsem zvědav, jak se to ujme – na jednu stranu je to ošklivé, na druhou stranu by ta ošklivost mohla vést k tomu, aby se nullable typy používaly jen minimálně, když je to opravdu nevyhnutelné.


JSH

Re:Rychlost Haskell vs. C++
« Odpověď #80 kdy: 27. 08. 2018, 00:46:15 »
Andy, pořád jsi nepochopil, jaká je strict vyhodnocení v Haskellu prasárna. Nevadí, zkusím to znovu. Změnit způsob vykonávání kódu a změnit sémantiku existujícího kódu jsou totiž dost rozdílné věci. Když píšeš třídu v C++, nemusíš přemýšlet o tom, jestli bude vytvořená na heapu nebo na stacku, bude fungovat v obou případech. Neexistuje žádné pragma stack ani pragma heap, které by měnilo sémantiku kódu ve třídě, podle toho, jestli je vytvořená na stacku nebo heapu. Pragma strict v Haskellu to ale dělá, kód který funguje bez pragma strict nemusí fungovat s ním a naopak. Úlpně to mení sémantiku kódu, nikoliv takové detaily, kde leží data, jestli na stacku nebo na heapu.
Ehm... To, jestli program zdechne na stack overflow, nebo bude v pohodě pracovat, je zatraceně velký rozdíl v sémantice.

andy

Re:Rychlost Haskell vs. C++
« Odpověď #81 kdy: 27. 08. 2018, 01:23:15 »
Andy, pořád jsi nepochopil, jaká je strict vyhodnocení v Haskellu prasárna. Nevadí, zkusím to znovu. Změnit způsob vykonávání kódu a změnit sémantiku existujícího kódu jsou totiž dost rozdílné věci. Když píšeš třídu v C++, nemusíš přemýšlet o tom, jestli bude vytvořená na heapu nebo na stacku, bude fungovat v obou případech. Neexistuje žádné pragma stack ani pragma heap, které by měnilo sémantiku kódu ve třídě, podle toho, jestli je vytvořená na stacku nebo heapu. Pragma strict v Haskellu to ale dělá, kód který funguje bez pragma strict nemusí fungovat s ním a naopak. Úlpně to mení sémantiku kódu, nikoliv takové detaily, kde leží data, jestli na stacku nebo na heapu.
Ehm... To, jestli program zdechne na stack overflow, nebo bude v pohodě pracovat, je zatraceně velký rozdíl v sémantice.
To asi není zrovna způsob, jak definovat sémantiku programu. On jakýkoliv program třeba může zdechnout v důsledku vyčerpání omezené paměti, a to může být závislé na nějakém optimalizačním flagu. Třeba v v C++ při vypnutí určitých optimalizací (rekurzivní funkce, dnešní překladače jsou schopny dělat tail-call optimalizaci).

Pod 'úplně jinou sémantikou' je ve funkcionálních jazycích myšleno, že to vrací něco jiného, nikoliv, že to potřebuje 100x tolik zdrojů. Jinak samozřejmě pokud označím jako strict nějakou bottom větev, která se v lazy případě ignoruje, tak to spadne bez ohledu na zdroje (třeba to nikdy neskončí).

Ale já pořád nerozumím tomu argumentu: co je špatného na existenci přepínače, který změní nějaké chování? To má přece spousta jazyků (strict režim JS..?). Nebo je špatně vůbec existence seq? Proč? Protože je špatné, když se dá jazyku říct, jak má co vykonávat? (třeba volatile)

lopata

Re:Rychlost Haskell vs. C++
« Odpověď #82 kdy: 27. 08. 2018, 12:19:45 »
volatile? V kombinaci s -O0 a -O2? To ti v multithreadovaným programu sakra změní sémantiku kódu.
Volatile nemá s multithreadingem nic společného, nedá se používat jako sychronizační primitivum. Použití volatile na sychronizaci v multithreading prostředí je prakticky vždy chyba. Neřeší to memory bariéry apod. Volatile pouze říká, že překladač nesmí na proměnné provádět optimalizace a musí ji vždy přečíst nebo zapsat z/do paměti. Pokud na takovém chování zavisíš a volatile nepoužiješ, tak je to vždy chyba nezávisle na úrovni optimalizace.

Úplně..? Jako že ti ta část kódu vrátí JINÝ výsledek? Fakt? Tak to by mě zajímalo, protože pokud vím, tak ta změna je maximálně v tom smyslu, že za určitých dost specifických okolností místo bottom vrátí smysluplný výsledek (fusion) nebo naopak místo výsledku to dá bottom. Tomu říkáš "úplně změní sémantiku kódu"?
Jako fakt to může dávat úplně jiné výsledky:
Kód: [Vybrat]
myDiv :: Float -> Float -> Float
myDiv x 0 = error "Division by zero"
myDiv x y = x / y

main =
  do
    let a = myDiv 1 2
    let b = myDiv 1 0
    print a
Kód: [Vybrat]
ghc -O2 test.hs
./test
0.5
ghc -O2 -XStrict test.hs
./test
test: Division by zero
CallStack (from HasCallStack):
  error, called at test.hs:2:13 in main:Main

andy

Re:Rychlost Haskell vs. C++
« Odpověď #83 kdy: 27. 08. 2018, 13:24:04 »
volatile? V kombinaci s -O0 a -O2? To ti v multithreadovaným programu sakra změní sémantiku kódu.
Volatile nemá s multithreadingem nic společného, nedá se používat jako sychronizační primitivum. Použití volatile na sychronizaci v multithreading prostředí je prakticky vždy chyba. Neřeší to memory bariéry apod. Volatile pouze říká, že překladač nesmí na proměnné provádět optimalizace a musí ji vždy přečíst nebo zapsat z/do paměti. Pokud na takovém chování zavisíš a volatile nepoužiješ, tak je to vždy chyba nezávisle na úrovni optimalizace.
Jistě - a program se pak chová jinak podle toho, který flag tomu dáš. Fajn, můžeš říct, že to je prostě blbě (a dle specifikaci asi celkem je). A co ta -ffast-math? Mění sémantiku práce s floating point operacema. Takže máš korektní kód, který se parametrem stane nekorektní..ale rychlejší. Taky problém?

Co 'use strict' v JS? V Perlu je myslím něco podobného.

Citace
Jako fakt to může dávat úplně jiné výsledky:
Kód: [Vybrat]
myDiv :: Float -> Float -> Float
myDiv x 0 = error "Division by zero"
myDiv x y = x / y

main =
  do
    let a = myDiv 1 2
    let b = myDiv 1 0
    print a
Kód: [Vybrat]
ghc -O2 test.hs
./test
0.5
ghc -O2 -XStrict test.hs
./test
test: Division by zero
CallStack (from HasCallStack):
  error, called at test.hs:2:13 in main:Main
Zajímavé, mě přišlo, že v jednom případě main vrátilo (), ve druhém bottom. Všechny funkce vrátily totéž nebo bottom. Máš na to jiný názor?  Jinak to, že v IO jsi schopen detekovat kompilační flagy je celkem pochopitelné. Ale tomu asi neříkáme, že to mění sémantiku programu...?

lopata

Re:Rychlost Haskell vs. C++
« Odpověď #84 kdy: 27. 08. 2018, 15:23:23 »
A co ta -ffast-math? Mění sémantiku práce s floating point operacema. Takže máš korektní kód, který se parametrem stane nekorektní..ale rychlejší. Taky problém?
Ano -ffast-math je taky prasárna, ne tak velká jako strict v Haskellu, ale pořád prasárna. Aby bylo jasno, já neobhajuju prasárny v jiných jazycích, jsou tam taky. Jenom tvrdím, že -XStrict v Haskellu je prasárna a docela velká. Ty tvrdíš, že -XStrict v Haskellu nevadí, protože ostatní jazyky jsou prasácké taky. Ano jsou, ale to přece není důvod zavádět prasárny i do Haskellu?

Zajímavé, mě přišlo, že v jednom případě main vrátilo (), ve druhém bottom. Všechny funkce vrátily totéž nebo bottom. Máš na to jiný názor?  Jinak to, že v IO jsi schopen detekovat kompilační flagy je celkem pochopitelné. Ale tomu asi neříkáme, že to mění sémantiku programu...?
Mě jako uživatele zajímá, jestli dostanu správný výsledek, nebo ne. Program bez -XStrict pracuje správně (protože závisí na lazy evaluation) a s -XStrict dostanu chybný výsledek. V tom programu přitom žádná chyba není, jen závisí na lazy evaluation a -XStrict ten program rozbije. -XStrict prostě úplně mění sémantiku vyhodnocování a může to korektní program rozbít. Můžeš klidně tvrdit, že main v jednom případě vrátilo () a ve druhém bottom, ale já jako uživatel chci, aby to vracelo správné výsledky stále, ne jenom v jednom případě.

A ještě jedna věc, vem si typickou lopatu, třeba mě, která by chtěla něco dělat v Haskellu. Mám problém, jsem lepič, nějaké řešení najdu na stackoverflow. Mám další problém, další řešení najdu na stackoverflow. Slepím to dohromady. A jsem úplně v háji protože nevím, která část kódu závisí na strict vyhodnocování a která ne. Musím tu informaci někde dohledávat a případně slepený kód pochopit a upravit, na správná místa přidat bang nebo lazy patterny, aby to fungovalo. Když to neudělám, tak se to přeloží, ale v určitých případech se to nemusí chovat správně. Tohle je úplně mimo možnosti běžné lopaty. S -ffast-math lopata mít problém nebude, prostě to přeloží bez -ffast-math a všechno bude fungovat, i když třeba pomaleji. Mimo jiné taky proto zůstane Haskell navždy akademickým jazykem a nestane se mainstreamem. Složitost v kombinaci se strict prasárnami ten jazyk dělá pro běžnou lopatu prakticky nepoužitelným. Bohužel, já mám Haskell rád a líbilo by se mi, kdyby se dal v mainstreamu používat, ale prakticky to zatím nevypadá na úspěch Haskellu.

JSH

Re:Rychlost Haskell vs. C++
« Odpověď #85 kdy: 27. 08. 2018, 15:32:45 »
Úplně..? Jako že ti ta část kódu vrátí JINÝ výsledek? Fakt? Tak to by mě zajímalo, protože pokud vím, tak ta změna je maximálně v tom smyslu, že za určitých dost specifických okolností místo bottom vrátí smysluplný výsledek (fusion) nebo naopak místo výsledku to dá bottom. Tomu říkáš "úplně změní sémantiku kódu"?
Jako fakt to může dávat úplně jiné výsledky:
Kód: [Vybrat]
myDiv :: Float -> Float -> Float
myDiv x 0 = error "Division by zero"
myDiv x y = x / y

main =
  do
    let a = myDiv 1 2
    let b = myDiv 1 0
    print a
Kód: [Vybrat]
ghc -O2 test.hs
./test
0.5
ghc -O2 -XStrict test.hs
./test
test: Division by zero
CallStack (from HasCallStack):
  error, called at test.hs:2:13 in main:Main
A nějaký prakticky zajímavý příklad by nebyl? Vyhodit nepoužitý blok kódu občas umí optimalizující překladače i ve strict jazycích. Jo, teoreticky je to změna sémantiky. Ale fakt mě nenapadá příklad, kdy by mi tahle změna sémantiky vadila při reálné práci.

lopata

Re:Rychlost Haskell vs. C++
« Odpověď #86 kdy: 27. 08. 2018, 15:51:34 »
A nějaký prakticky zajímavý příklad by nebyl? Vyhodit nepoužitý blok kódu občas umí optimalizující překladače i ve strict jazycích. Jo, teoreticky je to změna sémantiky.
Pokud má něco side effecty, tak to optimalizující překladač ve strict jazyce vyhodit nesmí a neudělá to (kromě přesně specifikovaných případů ve standardu jako třeba copy elision).

Ale fakt mě nenapadá příklad, kdy by mi tahle změna sémantiky vadila při reálné práci.
Nemáš moc velkou fantazii. Zkus se inspirovat třeba tady: https://www.reddit.com/r/haskell/comments/3sts2t/strict_haskell_xstrict_has_landed/

andy

Re:Rychlost Haskell vs. C++
« Odpověď #87 kdy: 27. 08. 2018, 16:25:35 »
A co ta -ffast-math? Mění sémantiku práce s floating point operacema. Takže máš korektní kód, který se parametrem stane nekorektní..ale rychlejší. Taky problém?
Ano -ffast-math je taky prasárna, ne tak velká jako strict v Haskellu, ale pořád prasárna. Aby bylo jasno, já neobhajuju prasárny v jiných jazycích, jsou tam taky. Jenom tvrdím, že -XStrict v Haskellu je prasárna a docela velká. Ty tvrdíš, že -XStrict v Haskellu nevadí, protože ostatní jazyky jsou prasácké taky. Ano jsou, ale to přece není důvod zavádět prasárny i do Haskellu?
Já nechápu tvoji logiku. Tvrdíš, že když -XStrict vyhodíš, tak se z Haskellu rázem stane skvělý jazyk?


Zajímavé, mě přišlo, že v jednom případě main vrátilo (), ve druhém bottom. Všechny funkce vrátily totéž nebo bottom. Máš na to jiný názor?  Jinak to, že v IO jsi schopen detekovat kompilační flagy je celkem pochopitelné. Ale tomu asi neříkáme, že to mění sémantiku programu...?
Mě jako uživatele zajímá, jestli dostanu správný výsledek, nebo ne. Program bez -XStrict pracuje správně (protože závisí na lazy evaluation) a s -XStrict dostanu chybný výsledek. V tom programu přitom žádná chyba není, jen závisí na lazy evaluation a -XStrict ten program rozbije. -XStrict prostě úplně mění sémantiku vyhodnocování a může to korektní program rozbít. Můžeš klidně tvrdit, že main v jednom případě vrátilo () a ve druhém bottom, ale já jako uživatel chci, aby to vracelo správné výsledky stále, ne jenom v jednom případě.
[/quote]
Takže na to, abys obhájil svůj názor, musíš argumentovat z pozice BFU. Já si nemyslím, že jsi BFU, ale všimni si, kam až musíš klesnout, abys ten názor obhjájil.... Haskell není pro BFU, to máš naprostou pravdu.
Ano, -XStrict mění způsob vyhodnocování a může to konkrétní program rozbít. A co? Tak to tam nepiš a nerozbije ti to.

Citace
A ještě jedna věc, vem si typickou lopatu, třeba mě, která by chtěla něco dělat v Haskellu. Mám problém, jsem lepič, nějaké řešení najdu na stackoverflow. Mám další problém, další řešení najdu na stackoverflow. Slepím to dohromady. A jsem úplně v háji protože nevím, která část kódu závisí na strict vyhodnocování a která ne. Musím tu informaci někde dohledávat a případně slepený kód pochopit a upravit, na správná místa přidat bang nebo lazy patterny, aby to fungovalo.
Dělám s Haskellem možná tak 5 let a na tohle jsem ještě nenarazil. Ono totiž asi tak 99% kódu se chová ve strict a lazy úplně stejně, akorát se to někdy liší ve výkonu (a někdy ani to ne, když to strictness analýza chytí.)

Citace
Složitost v kombinaci se strict prasárnami ten jazyk dělá pro běžnou lopatu prakticky nepoužitelným. Bohužel, já mám Haskell rád a líbilo by se mi, kdyby se dal v mainstreamu používat, ale prakticky to zatím nevypadá na úspěch Haskellu.
Když odstraní -XStrict, tak to tvůj názor změní? Oni to zavedli, protože se některým programátorům nechtělo všude psát '!'. Ale je vidět, že pro některé pouhá existence takového flagu je důvod poslat celý jazyk do háje....

andy

Re:Rychlost Haskell vs. C++
« Odpověď #88 kdy: 27. 08. 2018, 16:31:48 »
Ale fakt mě nenapadá příklad, kdy by mi tahle změna sémantiky vadila při reálné práci.
Nemáš moc velkou fantazii. Zkus se inspirovat třeba tady: https://www.reddit.com/r/haskell/comments/3sts2t/strict_haskell_xstrict_has_landed/
No při reálné práci člověk -XStrict nepoužije, pokud nepíše striktní kód. A když píše v haskellu striktní kód, tak asi ví, co dělá....prostě kód, který by ti v jiných jazycích spadnul, ti najednou spadne i v Haskellu, zatímco předtím by třeba kvůli laziness fungoval. Když použiješ -XStrict u kterýho víš, že přesně tenhle efekt mít bude...

andy

Re:Rychlost Haskell vs. C++
« Odpověď #89 kdy: 27. 08. 2018, 16:36:17 »
Bohužel, já mám Haskell rád a líbilo by se mi, kdyby se dal v mainstreamu používat, ale prakticky to zatím nevypadá na úspěch Haskellu.
Já ten pocit vůbec nemám, naopak - díky existenci velmi slušných knihoven pro práci s web aplikacemi mám pocit, že se v haskellu píše víc a víc věcí a naopak se začíná docela slušně prosazovat. A rozhodně rozšíření nezpomaluje to, že do 8.0 prosadil někdo, kdo potřeboval často psát strikt kód, pragmu -XStrict....