Scala vs. Java 8.

javaman ()

Re:Scala vs. Java 8.
« Odpověď #75 kdy: 27. 12. 2016, 20:29:05 »
Super, díky za info. Proti Pythonu to celkově vypadá jako jiná liga. Hlavně výkonem by to mělo být daleko lepší. Na skriptíky bych vůbec neváhal, jen zrovna žádné nedělám :D Zase Scala mi připadá jako moc malý skok od Javy, protože běží nad JVM, ale při nejhorším je to super kopromis. Vím, že Scala má zase asi jiné cool funkce, no.


Kit

Re:Scala vs. Java 8.
« Odpověď #76 kdy: 27. 12. 2016, 21:16:14 »
Je treba skarede pojmenovavat fieldy recordu (prefixovat jmenem recordu), takze kdyz se to vytvari pres record syntax, tak je to pekne ukecane (co teprv, kdyz se jmeno recordu sklada z nekolika slov, fuj).

Ten prefix si můžeš zkrátit až na jedno písmenko (zde jsme použili tři). Za prefix dáš místo podtržítka tečku a vypadá to i docela elegantně, skoro jako v OOP. Namespace je náš kamarád.

Dalsi nevyhoda je, ze si to samo nehlida, zda uz to v projektu danou type classu nevytvorilo, kontroluje se jen aktualni soubor, takze pak dochazi k takovym podivnostem, jakoze musim importovat do modulu s velocity modul s position, prestoze z nej nic "viditelne" nepouzivam, protoze oba pouzivaji stejny field a jinak se vytvori type class dvakrat a samozrejmne to umre.

Však jsem psal, že si vytvoříš modul Vector, ze kterého odvodíš position i velocity. Pozici pak měníš pouhým přičítáním velocity k position a nemusí tě trápit, zda je to ve 2D či 3D. Místo X a Y může být výhodnější [x,y]. Nebojuj s jazykem, využívej ho.

Radek Miček

Re:Scala vs. Java 8.
« Odpověď #77 kdy: 27. 12. 2016, 22:46:01 »
Č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í...

Docela by mne zajímalo, pro jaké lidi/týmy to platí a čím je to podložené. A také, zda to platí pouze pro vývoj nebo i pro údržbu.

Už jsme to tu řešili dříve a myslím si, že je to stále obrovský problém GHC - a sice snadné uvažování o rychlosti programu a určitá garance, že se rychlost prudce nezhorší při přechodu na novější verzi GHC nebo při malé změně v programu - viz třeba https://mail.haskell.org/pipermail/haskell-cafe/2016-July/124324.html:

Citace
The compilation method (and resulting runtime performance) depends on the GHC simplifier acting in a certain way — yet there is no specification of exactly what the simplifier should do, and no easy way to check that it did what was expected other than eyeballing the intermediate code.

gll

Re:Scala vs. Java 8.
« Odpověď #78 kdy: 27. 12. 2016, 23:50:38 »
Teď nedávno jsem potřeboval zpracovat rychle nějaký data - normálně jsem to dělával pythonem, krátký skriptík - zkusil jsem použít haskell a překvapivě to bylo vlastně stejně rychlé.

Docela by mě zajímalo, jak se v haskellu zpracovávají "nějaká data". Jak bys například přepsal tohle?

Kód: [Vybrat]
import requests
ua = requests.get(r'http://headers.jsontest.com/').json().get('User-Agent', '')

andy

Re:Scala vs. Java 8.
« Odpověď #79 kdy: 28. 12. 2016, 01:24:11 »
Č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í...
Docela by mne zajímalo, pro jaké lidi/týmy to platí a čím je to podložené. A také, zda to platí pouze pro vývoj nebo i pro údržbu.
Mě taky :) Pro údržbu tohle platí mnohem víc než jenom pro vývoj. Refaktoring v Haskellu je díky silným typům překvapivě záležitost, při které nevzniká mnoho chyb.

Citace
Už jsme to tu řešili dříve a myslím si, že je to stále obrovský problém GHC - a sice snadné uvažování o rychlosti programu a určitá garance, že se rychlost prudce nezhorší při přechodu na novější verzi GHC nebo při malé změně v programu - viz třeba https://mail.haskell.org/pipermail/haskell-cafe/2016-July/124324.html:

Citace
The compilation method (and resulting runtime performance) depends on the GHC simplifier acting in a certain way — yet there is no specification of exactly what the simplifier should do, and no easy way to check that it did what was expected other than eyeballing the intermediate code.
Ano - pokud máte hodně high-level jazyk, tak se holt dost špatně "jen tak" odhaduje, jak se to vlastně low-level bude chovat. Pro real-time aplikace to není (na druhou stranu existují projekty, kdy v haskellu píšete generátor kódu pro real-time), mimo jiné třeba i z důvodu GC. Ale připadá mi, že pro hodně projektů je korektnost kódu mnohem důležitější, než to, zda z HW vyždímete co nejvíc - a tragicky pomalé to rozhodně není (popravdě, je to v zásadě docela rychlé..)


andy

Re:Scala vs. Java 8.
« Odpověď #80 kdy: 28. 12. 2016, 01:59:18 »
Docela by mě zajímalo, jak se v haskellu zpracovávají "nějaká data". Jak bys například přepsal tohle?
Kód: [Vybrat]
import requests
ua = requests.get(r'http://headers.jsontest.com/').json().get('User-Agent', '')

Kód: [Vybrat]
{-# LANGUAGE OverloadedStrings #-}
import Network.Wreq (get, responseBody)
import Control.Lens ((^?), (<&>), preview)
import Data.Aeson.Lens (key)

main = do
  r <- get "http://headers.jsontest.com"
  let ua = r ^? responseBody . key "User-Agent"
  print r
Takhle to kompletně funguje a takhle bych to napsal. Kromě těch importů v podstatě totéž.

Aby to byl one-liner, tak se to dá pořešit třeba tímhle:
Kód: [Vybrat]
  r <- get "http://headers.jsontest.com" <&> preview (responseBody . key "User-Agent")
A výstup:
Kód: [Vybrat]
Just (String "haskell wreq-0.4.1.0")
Pokud by došlo k chybě dekódování nebo tam ten klíč chyběl, tak by z toho vypadlo Nothing. Pokud bys vyloženě chtěl, aby tam byl prázdný string, tak by se přidalo (<&> fromMaybe "").

BTW: responseBody ukazuje na ByteString, "key" je polymorfní lens, která na bytestringu funguje tak, že rovnou provede JSON dekódování; někdo se tu ptal, jak funguje setter - tak vzhledem k tomu, že tohle je lens, tak je možné provádět i updaty:
Kód: [Vybrat]
>  "[1,2,3]" & val . _Number %~ (+1)
"[2,3,4]"
> "[1,2,3]" & nth 1 . _Number %~ (+10)
"[1,12,3]"
Tzn. automaticky se to překonvertuje zpátky do stringu. Jako tohle v praxi asi moc užitečné není, ale je to docela zajímavé, co všechno je možné zrovna s lensama dělat :)

andy

Re:Scala vs. Java 8.
« Odpověď #81 kdy: 28. 12. 2016, 02:06:45 »
Errata:
Kód: [Vybrat]
print uaa na konci:
Kód: [Vybrat]
>  "[1,2,3]" & values . _Number %~ (+1)
Kdyby to někdo zkoušel....

Kit

Re:Scala vs. Java 8.
« Odpověď #82 kdy: 28. 12. 2016, 03:25:41 »
Docela by mě zajímalo, jak se v haskellu zpracovávají "nějaká data". Jak bys například přepsal tohle?
Kód: [Vybrat]
import requests
ua = requests.get(r'http://headers.jsontest.com/').json().get('User-Agent', '')

Kód: [Vybrat]
{-# LANGUAGE OverloadedStrings #-}
import Network.Wreq (get, responseBody)
import Control.Lens ((^?), (<&>), preview)
import Data.Aeson.Lens (key)

main = do
  r <- get "http://headers.jsontest.com"
  let ua = r ^? responseBody . key "User-Agent"
  print r
Takhle to kompletně funguje a takhle bych to napsal. Kromě těch importů v podstatě totéž.

Jednodušeji by to nešlo? Pomocí manuálů jsem se propracoval k tomuto:
Kód: [Vybrat]
import  Network.HTTP
resp = simpleHTTP(getRequest "http://headers.jsontest.com/")
main = do
    body <- resp >>= getResponseBody
    print body

Evidentně tomu ještě kousek chybí, ale určitě to nebude víc než jeden řádek.

andy

Re:Scala vs. Java 8.
« Odpověď #83 kdy: 28. 12. 2016, 09:11:50 »
Jednodušeji by to nešlo? Pomocí manuálů jsem se propracoval k tomuto:
Tak na počet znaků je to - kromě importů - identické. A ty importy znamenají: Web requesty (to je stejné), Json (u haskellu web request nic o jsonu neví), Lens (to python nemá) a OverloadedStrings je extension, protože v Haskellu se rozlišují různé typy stringů. Pak by ještě měl být import asi na to fromMaybe.
Citace
Kód: [Vybrat]
import  Network.HTTP
resp = simpleHTTP(getRequest "http://headers.jsontest.com/")
main = do
    body <- resp >>= getResponseBody
    print body
Evidentně tomu ještě kousek chybí, ale určitě to nebude víc než jeden řádek.
Chybí dekódování JSONu. Tzn. v podstatě ty zbývající importy a
Kód: [Vybrat]
print $ fromMaybe "" (body ^? key "User-Agent")
... což je totéž, co jsem napsal... Chtěl bych říct, že ty importy za tebe pořeší IDE, ale bohužel zatím ne.

Kit

Re:Scala vs. Java 8.
« Odpověď #84 kdy: 28. 12. 2016, 09:50:49 »
Jednodušeji by to nešlo? Pomocí manuálů jsem se propracoval k tomuto:
Tak na počet znaků je to - kromě importů - identické.

Identické to být nemůže, dělal jsem to samostatně. Kromě toho se chci vyhnout použití Lens.

Chybí dekódování JSONu. Tzn. v podstatě ty zbývající importy a
Kód: [Vybrat]
print $ fromMaybe "" (body ^? key "User-Agent")
... což je totéž, co jsem napsal... Chtěl bych říct, že ty importy za tebe pořeší IDE, ale bohužel zatím ne.

Nerozumím symbolu "^?", v manuálu Haskellu jsem ho zatím nenašel. Zato jsem tam našel HdrUserAgent, který by měl dělat totéž, co key "User-Agent".

Na parsování JSONu jsem našel Data.Aeson.

andy

Re:Scala vs. Java 8.
« Odpověď #85 kdy: 28. 12. 2016, 10:16:42 »
Nerozumím symbolu "^?", v manuálu Haskellu jsem ho zatím nenašel.
http://hoogle.haskell.org/?hoogle=%5E%3F
To jsou lensy (návod z Microlens je trošku čitelnější); tohle konkrétně je operátor, který vrací hodnotu, na kterou by mohla ukazovat lens (tzn. ta hodnota tam být nemusí). Kdyby v pythonu bylo:
Kód: [Vybrat]
obj.x.y.get('z', None)Tak tady by to bylo:
Kód: [Vybrat]
obj ^? x . y . key "z"
Citace
Zato jsem tam našel HdrUserAgent, který by měl dělat totéž, co key "User-Agent".
V tom původním příkladu se měla rozebrat JSON odpověd toho web serveru, ne hlavičky.

Citace
Na parsování JSONu jsem našel Data.Aeson.
To jo, ale to ti naparsuje JSON buď do tvého custom datového typu, nebo do "univerzální" struktury "Value". Ta lensa "key" je interně postavená na aesonu, ale zjednodušuje to kroky, které bys musel provést. Pokud víš co ti server vrátí, tak by ten kód pak vypadal třeba takhle (a v produkci by tak asi i možná skoro vypadal):
Kód: [Vybrat]
data ServerResponse = ServerResponse {
  userAgent :: Text
}
instance FromJSON ServerResponse where
   parseJSON = withObject "response" $ \o -> ServerResponse <$> o .: "User-Agent"
...
main = do
   ...
   case decode bodyResponse of
      Just resp -> print (userAgent resp)
      Nothing -> print "Chyba pri dekodovani"
Ale tady byla otázka "rychle prohledat nějaký JSON, který možná obsahuje klíč user-agent" - tak kvůli tomu asi nemá smysl vyrábět nový datový typ. Jinak aeson samozřejmě podporuje automatické generování (de)serializačního kódu.

Kit

Re:Scala vs. Java 8.
« Odpověď #86 kdy: 28. 12. 2016, 10:55:17 »
...
Ale tady byla otázka "rychle prohledat nějaký JSON, který možná obsahuje klíč user-agent" - tak kvůli tomu asi nemá smysl vyrábět nový datový typ. Jinak aeson samozřejmě podporuje automatické generování (de)serializačního kódu.

Mně ani tak nešlo o to, jak rychle dospět k nějakému cíli, ale jak pochopit Haskell jako jazyk. Samozřejmě se nechci vyhýbat Network.HTTP nebo Data.Aeson, ale třeba Lens mi už připadá jako zbytečnost navíc. Tedy zatím.

noef

  • *****
  • 897
    • Zobrazit profil
    • E-mail
Re:Scala vs. Java 8.
« Odpověď #87 kdy: 28. 12. 2016, 11:15:52 »
K tomu vyjadreni position i velocity jako vector - moc se mi to nelibi, uz jen proto, ze pak je validni priradit postion do velocity. Navic v tom mem projektu (ktery neni modelovani realneho sveta), je dost mozne, ze dospeju do stavu, kdy position bude nad celymi cisly, ale velocity ne. Pripadne position dostane dalsi field (napr. level ci dimension).

...
Ale tady byla otázka "rychle prohledat nějaký JSON, který možná obsahuje klíč user-agent" - tak kvůli tomu asi nemá smysl vyrábět nový datový typ. Jinak aeson samozřejmě podporuje automatické generování (de)serializačního kódu.

Mně ani tak nešlo o to, jak rychle dospět k nějakému cíli, ale jak pochopit Haskell jako jazyk. Samozřejmě se nechci vyhýbat Network.HTTP nebo Data.Aeson, ale třeba Lens mi už připadá jako zbytečnost navíc. Tedy zatím.

IMO pokud to myslite s FP vazne, tak se lens nevyhnete, protoze jinak musite psat a udrzovat haldy boilerplate kodu. Proto jsem se se ptal, jestli pro Javu nejaka lens knihovna existuje, protoze bez toho si FP nedovedu moc predstavit. Pro Scalu jsem priklady uvedl - obe knihovny umi i autogenerovani, takze kodu navic je minimum.

Kit

Re:Scala vs. Java 8.
« Odpověď #88 kdy: 28. 12. 2016, 11:39:25 »
K tomu vyjadreni position i velocity jako vector - moc se mi to nelibi, uz jen proto, ze pak je validni priradit postion do velocity. Navic v tom mem projektu (ktery neni modelovani realneho sveta), je dost mozne, ze dospeju do stavu, kdy position bude nad celymi cisly, ale velocity ne. Pripadne position dostane dalsi field (napr. level ci dimension).

Uvedl jsem to jen jako možnost. Nic nebrání rozdělení podle sémantiky.

IMO pokud to myslite s FP vazne, tak se lens nevyhnete, protoze jinak musite psat a udrzovat haldy boilerplate kodu. Proto jsem se se ptal, jestli pro Javu nejaka lens knihovna existuje, protoze bez toho si FP nedovedu moc predstavit. Pro Scalu jsem priklady uvedl - obe knihovny umi i autogenerovani, takze kodu navic je minimum.

V OOP se obejdu bez getterů, setterů a veřejných atributů. Ve FP se určitě obejdu bez lens, aniž bych musel psát boilerplates. Přinejhorším si je nechám vygenerovat editorem a upravím na přesnou míru.

andy

Re:Scala vs. Java 8.
« Odpověď #89 kdy: 28. 12. 2016, 12:25:10 »
V OOP se obejdu bez getterů, setterů a veřejných atributů. Ve FP se určitě obejdu bez lens, aniž bych musel psát boilerplates. Přinejhorším si je nechám vygenerovat editorem a upravím na přesnou míru.
Tak pro začátek určitě ano - dokud člověk nezačne nějak víc pracovat s vnořenými strukturami, tak se fakt bez Lens obejde; a ony ty vnořené struktury až tak časté v kódu nejsou. Ostatně i ten příklad s user-agentem - pokud by to byla nějaká REST služba, tak bude mít asi definovaný nějaký interface, takže se k tomu udělají odpovídající struktury v programu a vygeneruje se serializace/deserializace. Ono je docela rozumné, když člověk ví aspoň rámcově, co to dělá, a lensy jsou fakt magie. Na druhou stranu při práci s vnořenými strukturami - a to třeba "generický" json je - je to bez lens silně nepohodlné.

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). No a FP programátor sice nutně neprahne po tom každou výjimku ošetřovat, ale docela by rád, aby ta funkce byla "totální" - tzn. pro jakýkoliv vstup to "skončí" (tzn. nevyhodí výjimku, ale něco vrátí). No a kombinace lens a Maybe Monad pak umožňuje tu funkci napsat jako:
Kód: [Vybrat]
f someJson = do
   num <- someJson ^? key "key" . nth 3 . key "nextkey"
   return (num + 1)
a ač to na první pohled nevypadá, tak tahle funkce je totální a vrátí buď výsledek nebo Nothing a nevyhodí výjimku (pokud to nevyhodí (+)). Bez lens by to asi nějak šlo, kdyby si člověk napsal vhodné funkce, tak by to mohlo i vypadat:
Kód: [Vybrat]
f someJson = do
   num <- getKey "key" someJson >>= getNth 3 >>= getKey "nextKey"
   return (num + 1)
Ale už to není tak elegantní a hlavně jakákoliv modifikace té vnořené struktury by už fakt byla problém.