Scala vs. Java 8.

andy

Re:Scala vs. Java 8.
« Odpověď #105 kdy: 29. 12. 2016, 00:58:32 »
Citace
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.
Ne, musíš to kompilovat s -O, což je ale standardní režim kompilace pro veškeré cabal projekty. Naopak, když to chceš kompilovat bez optimalizací, musíš to kompilovat s -O0. Tys to asi kompiloval přímo s GHC, to to má možná defaultně vypnuté, ale takhle se nic nevyvíjí. Dneska se docela často na vývoj používá stack.
Citace
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.
Protože spousta algoritmů je moc hezky popsána rekurzivně - tak proč to tak nepsat.

Mimochodem, v Haskellu není rekurze úplně typický design pattern. Typický design pattern je používat právě ty funkce typu "fold" - proto je u toho "foldl" všude ten velký vykřičník, protože to je typický design pattern (a typický výjimka z něho).
Citace
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?
A proč by to nemělo jít vypnout? Když už se v tomhle hrabeš, tak se tak nějak předpokládá, že víš, co děláš. Ona mimochodem ta optimalizace se dá trošku řídit (Rewrite rules) a když v tom třeba hledáš chybu, tak jsi docela rád, že se dá s těma optimalizacema štelovat. Další věc je, že ten překladač se velmi zajímavě vyvíjí a sem tam někdo na světě narazí na něco, co se třeba nepřeložilo dobře - tak je dobré mít způsob, jak ten problém vůbec najít.

Mimochodem, Scala pokud vím tail-call optimalizaci má dost problematickou, protože JRE to neumí - a to je pak trošku větší problém.


gll

Re:Scala vs. Java 8.
« Odpověď #106 kdy: 29. 12. 2016, 01:17:00 »
Protože spousta algoritmů je moc hezky popsána rekurzivně - tak proč to tak nepsat.

Pomocí tail-call optimalizovatelné rekurze zapíšete jen algoritmy, které se dají snadno zapsat smyčkou.

andy

Re:Scala vs. Java 8.
« Odpověď #107 kdy: 29. 12. 2016, 01:18:09 »
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.
Agresivní :) Když chceš převést Nothing na 0, tak napíšeš "fromMaybe 0 x" a je to. Ale tohle je spíš taková všeobecná otázka - jak psát kód. A mně se třeba líbí, že mě Haskell donutí explicitně ošetřit drtivou většinu hraničních stavů. Když něco neošetřím, tak se to typicky nezkompiluje, nebo vyskáčou warningy. Ty nástroje na ošetření těch stavů jsou dost propracované, takže to fakt není to typické "pokud chyba, tak..". Ono pak se ti prakticky nestane, že někde něco zapomeneš ošetřit a vzniká daleko menší prostor pro to, aby ti třeba nějaký hacker zatopil....
Citace
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.
...write-only kód? Aneb aby ten, kdo to čte, byl zhruba 2x geniálnější než ten, kdo to píše...fakt netuším, co to dělá a to teda ani náznakem.

Citace
Jak se chová v Haskelu např. "+" v následujícím případě?
Kód: [Vybrat]
perl6 -e 'say "12" + 1' #13
Nepřeloží se to. Bůhví, co programátor pil, když chce po počítači sečíst řetězec a číslo.

andy

Re:Scala vs. Java 8.
« Odpověď #108 kdy: 29. 12. 2016, 01:19:43 »
Protože spousta algoritmů je moc hezky popsána rekurzivně - tak proč to tak nepsat.
Pomocí tail-call optimalizovatelné rekurze zapíšete jen algoritmy, které se dají snadno zapsat smyčkou.
Ta funkce nemusí volat jenom sama sebe.

gll

Re:Scala vs. Java 8.
« Odpověď #109 kdy: 29. 12. 2016, 01:35:20 »
Citace
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.
...write-only kód? Aneb aby ten, kdo to čte, byl zhruba 2x geniálnější než ten, kdo to píše...fakt netuším, co to dělá a to teda ani náznakem.

To stejné můžete říct o každém jazyce, o kterém jste si nic nepřečetl.

https://docs.perl6.org/language/variables#The_%_Variable

https://docs.perl6.org/language/variables#The_$_Variable

https://docs.perl6.org/language/variables#The_$__Variable


andy

Re:Scala vs. Java 8.
« Odpověď #110 kdy: 29. 12. 2016, 02:08:49 »
To stejné můžete říct o každém jazyce, o kterém jste si nic nepřečetl.
Až na to, že jsem před docela mnoha lety s Perlem strávil docela dost času. Napsal jsem v tom takový větší program, vrátil jsem se k tomu za 3 měsíce vůbec jsem netušil, co to dělá. Takhle extrémně se mi to nikdy předtím ani potom nestalo. Mně to fakt připadá jako "executable line-noise", protože si to kvantum paznaků fakt zapamatovat nedokážu. Ale dobře, asi tuším.....jak moc si jste jistý, když něco takového napíšete, že v tom není chyba?

Jinak tohle je pěkný příklad kódu, který se zrovna v haskellu takhle krátce fakt nenapíše - silně mutable a "protkaný" efekty. Na takovéhle hacky to fakt není :)

wamba

Re:Scala vs. Java 8.
« Odpověď #111 kdy: 29. 12. 2016, 03:21:56 »
A mně se třeba líbí, že mě Haskell donutí explicitně ošetřit drtivou většinu hraničních stavů. Když něco neošetřím, tak se to typicky nezkompiluje, nebo vyskáčou warningy.
A před chvílí jste vyčítal Pythonu to, že vyhodí výjimku, a teď si v tom libujete. Opět je to o přístupu.
Kód: [Vybrat]
perl6 -e 'for lines() { say join ";\t",++$,$_, ++(%){ .split(":")[*-1] } }' /etc/passwd ...write-only kód? Aneb aby ten, kdo to čte, byl zhruba 2x geniálnější než ten, kdo to píše...fakt netuším, co to dělá a to teda ani náznakem.
Ano, je to nečitelné, ale jednak one-liner to snese a  je to úplný příklad, který si lze ozkoušet. Nedělejte si iluze, že vaše příklady v Haskellu jsou všem srozumitelné.
Citace
Jak se chová v Haskelu např. "+" v následujícím případě?
Kód: [Vybrat]
perl6 -e 'say "12" + 1' #13
Nepřeloží se to. Bůhví, co programátor pil, když chce po počítači sečíst řetězec a číslo.
Takže sečítat Nothink s číslem je v pořádku, ale řetězec obsahující číslo s číslem už ne?
Využítí viz
Kód: [Vybrat]
perl6 -e 'my $text="2 8 4 7"; put $text.words.map: * + 1' #3 9 5 8   

noef

  • *****
  • 897
    • Zobrazit profil
    • E-mail
Re:Scala vs. Java 8.
« Odpověď #112 kdy: 29. 12. 2016, 07:02:22 »
...
Takže sečítat Nothink s číslem je v pořádku, ale řetězec obsahující číslo s číslem už ne?

Nothing se nikde s cislem nesecita :D. Operator "<-" (prepise se na operaci bind) to z Maybe monady "vybali" a scita se cislo s cislem.

v

Re:Scala vs. Java 8.
« Odpověď #113 kdy: 29. 12. 2016, 08:55:22 »
Kód: [Vybrat]
[quote]
perl6 -e 'my $text="2 8 4 7"; put $text.words.map: * + 1' #3 9 5 8

[/quote]

perl6 -e 'my $text="2 ? 4 7"; put $text.words.map: * + 1' #3 9 5 8
Cannot convert string to number: base-10 number must begin with valid digits or '.' in '⏏?' (indicated by ⏏)
  in block <unit> at -e:1

Actually thrown at:
  in block <unit> at -e:1

pro srovnání:
Prelude> import Text.Read
Prelude Text.Read> fmap (fmap (+(1::Int))) $ fmap readMaybe $ words "2 ? 4 7"
[Just 3,Nothing,Just 5,Just 8]


andy

Re:Scala vs. Java 8.
« Odpověď #114 kdy: 29. 12. 2016, 08:58:15 »
A mně se třeba líbí, že mě Haskell donutí explicitně ošetřit drtivou většinu hraničních stavů. Když něco neošetřím, tak se to typicky nezkompiluje, nebo vyskáčou warningy.
A před chvílí jste vyčítal Pythonu to, že vyhodí výjimku, a teď si v tom libujete. Opět je to o přístupu.
Já to pythonu nevyčítal - IMO to je výrazně lepší přístup než v Perlu. Psal jsem, že s tou návratovou hodnotou se lépe pracuje. Třeba konkrétně víte, co vám funkce vrátí. Python checked exceptions nemá, takže to netušíte. Java je třeba má, ale ta práce s nimi taky není zrovna pohodlná - viz příklad od "v".
Citace
příklady v Haskellu jsou všem srozumitelné.
To si nedělám - protože ten jazyk je úplně jiný, než imperativní jazyky. Ale když se na svůj kód podívám po roce, tak mu aspoň sám kupodivu rozumím. Ale tohle není o jazyce - ona je to hezká soutěž snažit se napsat všechno na jednom řádku - v FP se něčemu podobnému říká point-free style. Akorát že když se to přežene, tak z toho fakt není poznat, co to vlastně dělá - proto to normální lidi používají dost střídmě.
Kód: [Vybrat]
f = (1 +) . ap ((+) . join (*)) (2 *) -- totéž jako: f x = x*x + 2*x + 1
Akorát, že Perlisti se v tom evidentně vyžívají a psaní write-only kódu považují za výhodu....

Citace
perl6 -e 'my $text="2 8 4 7"; put $text.words.map: * + 1' #3 9 5 8
Ono řešit, jestli jsou na vstupu vůbec korektní data, není dneska zrovna v módě....že někde za běhu vyskakují warningy je opravdu zajímavé - kdo je čte?

Radek Miček

Re:Scala vs. Java 8.
« Odpověď #115 kdy: 29. 12. 2016, 23:26:38 »
Citace
Citace
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.
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.

Nemám vyzkoušeno, ale myslím, že na stack overflow budou padat např. implementace Eq a Ord vygenerované pomocí deriving pro stromové struktury, které mají alespoň 2 větve (např. binární stromy). Konkrétně, když budou porovnávané struktury hlubší (např. 10 milionů nebo 100 milionů vnoření) ve více větvích. Ale to se děje prakticky ve všech populárních funkcionálních jazycích.

Citace
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í

Je otázka, zda není špatně, že optimalizace udělá z nefunkčnícho programu program funkční. Navíc je otázkou, jak jsou takové optimalizace robustní - jestli malá změna v programu na jiném místě nezpůsobí nečekané vypnutí této optimalizace a program pak přestane pracovat správně.

andy

Re:Scala vs. Java 8.
« Odpověď #116 kdy: 30. 12. 2016, 21:06:57 »
Je otázka, zda není špatně, že optimalizace udělá z nefunkčnícho programu program funkční. Navíc je otázkou, jak jsou takové optimalizace robustní - jestli malá změna v programu na jiném místě nezpůsobí nečekané vypnutí této optimalizace a program pak přestane pracovat správně.
Špatně je, pokud je program postavený na tom, že to takhle funguje... Ale teď jsem někde zahlédl supr příklad (z hlavy, nezkoušel jsem):
Kód: [Vybrat]
import Data.Vector as V
take 5 $ V.toList $ V.fromList [1..]
Když se to korektně zfůzuje, tak ten kód skončí. Ale fakt nejsem schopen odpovědět na otázku, jestli je to dobře nebo špatně, protože když už to ten výsledek vrátí, tak je vlastně korektní.....