Rychlost Haskell vs. C++

Re:Rychlost Haskell vs. C++
« Odpověď #90 kdy: 27. 08. 2018, 17:31:58 »
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.

Pokud to poslepuješ z "fungujících kousků kódu", tak se dostaneme na úroveň tohoto:

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. (...)

čili, bude to fungovat vždy, jen bude případně problém s výkonem. (pragma bude mít jen ten kód, co to potřebuje, protože to při a) lepení budeš vědět - tedy necháš to pouze na onom souboru b) vědět to nebudeš a tím pádem to bude možná akorát tak pomalejší s lazy eval.)


lopata

Re:Rychlost Haskell vs. C++
« Odpověď #91 kdy: 27. 08. 2018, 17:54:08 »
čili, bude to fungovat vždy, jen bude případně problém s výkonem. (pragma bude mít jen ten kód, co to potřebuje, protože to při a) lepení budeš vědět - tedy necháš to pouze na onom souboru b) vědět to nebudeš a tím pádem to bude možná akorát tak pomalejší s lazy eval.)
Ty jsi nepochopil, jak to funguje. Pokud je kód v Haskellu napsaný s předpokladem lazy evaluation, tak ho strict evaluation může rozbít. Funguje to i naopak. Pokud je kód v Haskellu napsaný s předpokladem strict evaluation, může ho lazy evaluation rozbít. Nebude to jenom pomalejší s lazy/strict evaluation, nemusí to vůbec fungovat. Takže když něco poslepuješ dohromady, máš potenciální problém. Musíš vědět, s jakým předpokladem byl ten kód napsán a upravovat ho bang patterny podle toho, která část závisí na lazy a která na strict a taky podle toho, jestli to překládáš s XStrict, nebo ne.

Dále bych se k tomu už asi nevyjadřoval, myslím že bylo vše podstatné řečeno a točíme se v kruhu.

andy

Re:Rychlost Haskell vs. C++
« Odpověď #92 kdy: 27. 08. 2018, 19:57:03 »
Funguje to i naopak. Pokud je kód v Haskellu napsaný s předpokladem strict evaluation, může ho lazy evaluation rozbít. Nebude to jenom pomalejší s lazy/strict evaluation, nemusí to vůbec fungovat.
Ne, bude to jenom pomalejší a může to mít brutálně větší nároky na paměť, ale fungovat to bude. Je to zhruba na stejné úrovni, jako když v C++ napíšeš rekurzivní funkci a spolehneš se na tail call optimalizaci, a pak to někdo přeloží bez optimalizace. Další "nevinný" switch, který "mění sémantiku"..?

 
Citace
Takže když něco poslepuješ dohromady, máš potenciální problém. Musíš vědět, s jakým předpokladem byl ten kód napsán a upravovat ho bang patterny podle toho, která část závisí na lazy a která na strict a taky podle toho, jestli to překládáš s XStrict, nebo ne.
Ano, Haskell není pro lepiče. Nadávání na lepiče, kteří pospojují kousky ze stackoverflow, jak zkompletují kód kterýmu nerozumí a on potom nefunguje je všude dost... ano, haskell pro takové lidi není.

Jinak:

- XStrict prakticky nikdo nepoužívá; to je prostě flag pro pokusy s výpočetními úlohami, je to naprosto okrajové
- Osobně jsem se za 5 let programování v haskellu nesetkal ani jednou se situací, kdy bych něco udělal strict a ono to přestalo fungovat. Popravdě mi připadá, že fakt, že se otáčíš na tomhle je spíš znakem, že jsi v tom neprogramoval, protože ta "změna sémantiky" prostě v praxi problém není. Kromě toho, že v praxi XStrict na "normální" kód prostě nikdo nepoužívá.
- Problém "lazy" evaluace jsou spíš memory leaky - stává se to zřídka. Ale u většího projektu se tak 1-2 povedou a je to strašná otrava to hledat.

lopata

Re:Rychlost Haskell vs. C++
« Odpověď #93 kdy: 27. 08. 2018, 20:25:14 »
Funguje to i naopak. Pokud je kód v Haskellu napsaný s předpokladem strict evaluation, může ho lazy evaluation rozbít. Nebude to jenom pomalejší s lazy/strict evaluation, nemusí to vůbec fungovat.
Ne, bude to jenom pomalejší a může to mít brutálně větší nároky na paměť, ale fungovat to bude. Je to zhruba na stejné úrovni, jako když v C++ napíšeš rekurzivní funkci a spolehneš se na tail call optimalizaci, a pak to někdo přeloží bez optimalizace. Další "nevinný" switch, který "mění sémantiku"..?
Už opravdu naposledy. Pokud má observable efekty (tím myslím změnu výstupu programu) zapnutí XStrict, je celkem jasné, že observable efekty bude mít i vypnutí XStrict. Za domácí úkol si můžeš zkusit napsat kód, který s XStrict funguje a bez XStrict ne. Není to nic složitého.

Osobně jsem se za 5 let programování v haskellu nesetkal ani jednou se situací, kdy bych něco udělal strict a ono to přestalo fungovat. Popravdě mi připadá, že fakt, že se otáčíš na tomhle je spíš znakem, že jsi v tom neprogramoval, protože ta "změna sémantiky" prostě v praxi problém není. Kromě toho, že v praxi XStrict na "normální" kód prostě nikdo nepoužívá.
Ty v tom programuješ 5 let a stejně nejsi schopen domyslet, jaké důsledky má změna lazy versus strict vyhodnocení, Haskell asi opravdu není pro každého ;). Jen vtip, neber si to osobně.

andy

Re:Rychlost Haskell vs. C++
« Odpověď #94 kdy: 27. 08. 2018, 20:55:54 »
Funguje to i naopak. Pokud je kód v Haskellu napsaný s předpokladem strict evaluation, může ho lazy evaluation rozbít. Nebude to jenom pomalejší s lazy/strict evaluation, nemusí to vůbec fungovat.
Ne, bude to jenom pomalejší a může to mít brutálně větší nároky na paměť, ale fungovat to bude. Je to zhruba na stejné úrovni, jako když v C++ napíšeš rekurzivní funkci a spolehneš se na tail call optimalizaci, a pak to někdo přeloží bez optimalizace. Další "nevinný" switch, který "mění sémantiku"..?
Pokud má observable efekty (tím myslím změnu výstupu programu) zapnutí XStrict, je celkem jasné, že observable efekty bude mít i vypnutí XStrict. Za domácí úkol si můžeš zkusit napsat kód, který s XStrict funguje a bez XStrict ne. Není to nic složitého.
Víš, mě připadá, že ses dostal do naprosto absurdní situace z hlediska toho, čím se snažíš tvou tezi obhájit. Začali jsme tím, že část kódu nevrátí jinou hodnotu, maximálně bottom. To jsi musel předefinovat, že lopatě to je jedno, co to vrací, ale že se celý program chová jinak. Ano, lopatě to fakt jedno je, programátor by v tom mohl vidět rozdíl. No, a pak tady je teze, že Lazy->Strict rozbije program, z čehož vůbec nevyplývá, že by Strict->Lazy mohlo rozbít program - no a abys opět dokázal, že máš pravdu, tak pod pojmem "rozbije program" rozumíš "má observable efekt"... Samozřejmě v IO jsi schopen pozorovat "observable efekty" (třeba timing), takže není problém napsat (v jakémkoliv programovacím jazyce) program, který se "rozbije" při jakékoliv změně nějakého flagu....

Jo, "Strict" je trošku drsnější pragma, kterou prakticky nikdo v normálním kódu nepoužívá, ale pro někoho, kdo lepí kód ze stackoverflow to je problém, protože možná někdo v nějaké odpovědi, které nerozumí, zrovna ten "nenormální kód" někdo pastnul...


lopata

Re:Rychlost Haskell vs. C++
« Odpověď #95 kdy: 27. 08. 2018, 21:57:02 »
...
Čti co píšu a používej hlavu, nemotej do toho timing a podobné hovadiny: Pokud má observable efekty (tím myslím změnu výstupu programu) zapnutí XStrict, je celkem jasné, že observable efekty bude mít i vypnutí XStrict.

andy

Re:Rychlost Haskell vs. C++
« Odpověď #96 kdy: 27. 08. 2018, 22:26:07 »
...
Čti co píšu a používej hlavu, nemotej do toho timing a podobné hovadiny: Pokud má observable efekty (tím myslím změnu výstupu programu) zapnutí XStrict, je celkem jasné, že observable efekty bude mít i vypnutí XStrict.
Chceš snad říct, že tvrdím opak?

andy

Re:Rychlost Haskell vs. C++
« Odpověď #97 kdy: 27. 08. 2018, 22:30:49 »
...
Čti co píšu a používej hlavu, nemotej do toho timing a podobné hovadiny: Pokud má observable efekty (tím myslím změnu výstupu programu) zapnutí XStrict, je celkem jasné, že observable efekty bude mít i vypnutí XStrict.
A napsat program, jehož výstup se mění na základě timingu nějaké funkce je snad nějaký problém, btw?

Re:Rychlost Haskell vs. C++
« Odpověď #98 kdy: 27. 08. 2018, 23:14:30 »
Ty jsi nepochopil, jak to funguje. Pokud je kód v Haskellu napsaný s předpokladem lazy evaluation, tak ho strict evaluation může rozbít. (...)

Tak to bych rád viděl nějaký příklad, ať si doplním znalosti. Za tu dobu, co v Haskellu dělám, jsem na podobný případ nenarazil. :)

lopata

Re:Rychlost Haskell vs. C++
« Odpověď #99 kdy: 28. 08. 2018, 05:54:02 »
Ty jsi nepochopil, jak to funguje. Pokud je kód v Haskellu napsaný s předpokladem lazy evaluation, tak ho strict evaluation může rozbít. (...)

Tak to bych rád viděl nějaký příklad, ať si doplním znalosti. Za tu dobu, co v Haskellu dělám, jsem na podobný případ nenarazil. :)

Opakování je matka moudrosti:
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

Lazy:
Kód: [Vybrat]
ghc -O2 test.hs
./test
0.5

Strict:
Kód: [Vybrat]
ghc -O2 -XStrict test.hs
./test
test: Division by zero
CallStack (from HasCallStack):
  error, called at test.hs:2:13 in main:Main

Více pro inspiraci zde: https://www.reddit.com/r/haskell/comments/3sts2t/strict_haskell_xstrict_has_landed/

Re:Rychlost Haskell vs. C++
« Odpověď #100 kdy: 28. 08. 2018, 06:52:25 »
@lopata: Omlouvám se, špatná citace - měl jsem namysli opačný směr, tj. jak lazy evaluation může rozbít "strict předpokládající" kód. Sorry. :) Na tento případ bys příklad měl?


Re:Rychlost Haskell vs. C++
« Odpověď #101 kdy: 28. 08. 2018, 07:00:58 »
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

Lazy:
Kód: [Vybrat]
ghc -O2 test.hs
./test
0.5

Strict:
Kód: [Vybrat]
ghc -O2 -XStrict test.hs
./test
test: Division by zero
CallStack (from HasCallStack):
  error, called at test.hs:2:13 in main:Main

imho zrovna v tomto případě bych "čekal", že to optimalizuje kompilátor a onen "vadný řádek" vyhodí (tak jako třeba v C) - zvlášť když zapínáš optimalizace.

lopata

Re:Rychlost Haskell vs. C++
« Odpověď #102 kdy: 28. 08. 2018, 07:20:26 »
imho zrovna v tomto případě bych "čekal", že to optimalizuje kompilátor a onen "vadný řádek" vyhodí (tak jako třeba v C) - zvlášť když zapínáš optimalizace.
Tak to bys čekal špatně. Kompilátor to NESMÍ vyhodit, protože to má při strict vyhodnocení observable side-effects. Nesmí to vyhodit ani v C ani v Haskellu, v tom není žádný rozdíl.

Re:Rychlost Haskell vs. C++
« Odpověď #103 kdy: 28. 08. 2018, 08:07:55 »
imho zrovna v tomto případě bych "čekal", že to optimalizuje kompilátor a onen "vadný řádek" vyhodí (tak jako třeba v C) - zvlášť když zapínáš optimalizace.
Tak to bys čekal špatně. Kompilátor to NESMÍ vyhodit, protože to má při strict vyhodnocení observable side-effects. Nesmí to vyhodit ani v C ani v Haskellu, v tom není žádný rozdíl.

Kód: [Vybrat]
1 #include <stdio.h>
 2 #include <stdlib.h>
 3
 4 int main(void) {
 5     int x = 9;
 6     int* ptr1 = &x;
 7     int* ptr2 = NULL;
 8
 9      int q = *ptr1;
10     int y = *(ptr2);
11     printf("x: %d\n", q);
12
13     return 0;
14 }
15

Zkus to zkompilovat takto:

Kód: [Vybrat]
gcc -O2 test.c -o test
pak takto:

Kód: [Vybrat]
gcc test.c -o test
a nakonec to modifikuj tak, aby se výraz
Kód: [Vybrat]
*(ptr2) neukládal do proměnné. :)

Btw nejsem si jist, že "observable side-effects" používáš korektně.
Btw2 ten příklad na rozbití "strict" kódu přes lazy evaluation by nebyl? Opravdu mě to zajímá. :)

andy

Re:Rychlost Haskell vs. C++
« Odpověď #104 kdy: 28. 08. 2018, 08:14:38 »
@lopata: Omlouvám se, špatná citace - měl jsem namysli opačný směr, tj. jak lazy evaluation může rozbít "strict předpokládající" kód. Sorry. :) Na tento případ bys příklad měl?
Ano, taky na to čekám...
Citace
    Funguje to i naopak. Pokud je kód v Haskellu napsaný s předpokladem strict evaluation, může ho lazy evaluation rozbít. Nebude to jenom pomalejší s lazy/strict evaluation, nemusí to vůbec fungovat.
A za tím jsem se dozvěděl, že "observable side effect" === "rozbít".... Jako ono samozřejmě je možné v IO napsat:

Kód: [Vybrat]
{-# LANGUAGE ScopedTypeVariables #-}
import Control.Exception (try, SomeException, evaluate)

myConst a b = a
main = do
  res <- try (evaluate (myConst () undefined))
  case res of
    Right () -> error "Je to rozbity"
    Left (_ :: SomeException) -> putStrLn "Funguje to"
Ale to se přesně dostáváme k tomu, že tímhle způsobem umíme "rozbít" kód jakéhokoliv jazyka jakoukoliv optionou překladu, která má "nějaký" vliv, třeba na timing....