V tomhle díle mě zaujala věta "ovšem ve skutečnosti se výsledky ukládají do vyrovnávací paměti, takže někdy k vyhodnocení nedochází". Dá se počítat ještě u něčeho s ukládáním výsledků? Třeba u výpočtu funkcí se stejnými výsledky? Pokud ano, jak Clojure pozná, že uvnitř není použito třeba (rand)?
Názory k článku
Clojure a bezpečné aplikace pro JVM: sekvence, lazy sekvence a paralelní programy
Re: cachování výpočtů
celé vláknoTo je zajimava otazka a dekuji za ni. Plati, ze prvky lazy sekvence zustanou v pameti tak dlouho, dokud na tuto sekvenci existuje reference, tj. (kdyz to prevedu do Javovske reci) existuje promenna ci parametr, ktery referencuje objekty typu sekvence. Funguje to tak, ze napriklad pri druhem volani funkce "nth" nebo "take" se uz prvky vyhodnotit nemusi, ovsem predpoklada se, ze se pouzivaji ciste funkce bez vedlejsiho efektu, coz rand neni :-) [nekde je ulozen predchozi stav generatoru pseudonahodnych cisel, ktery se volanim (rand) zmeni].
Re: cachování výpočtů
celé vláknoAsi uvedu i priklad, doufam, ze projde formatovani. Mejme jednoduchou funkci:
(defn increment
[x]
(do
(println "computing " x)
(inc x)))
u ni je zajimave, ze jako vedlejsi efekt pri svem zavolani "neco" vypise na stdout.
Ted vytvorime lazy sekvenci:
(def mysequence (map increment (range 1 10)))
... a nic se nevypsalo! protoze Clojure je liny lazy sekvenci vyhodnocovat - ostatne ani nemusi, alespon prozatim :)
Ziskame prvni 4 prvky:
(take 4 mysequence) (computing 1 computing 2 computing 3 computing 4 computing 5 computing 6 computing 7 computing 8 computing 9 2 3 4 5)
ted doslo k vyhodnoceni sekvence, coz prozradi printy - vedlejsi efekt
A co kdyz "take" zavolame znovu?:
(take 4 mysequence) (2 3 4 5)
nic se krome navratove hodnoty take nevypsalo = uz se nase funkce nevola protoze mame vysledky "cachovany"
Re: cachování výpočtů
celé vláknoTo sice vypadá zajímavě, ale nelíbí se mi, že se to dělá automaticky a tímpádem programátor musí myslet na to, jestli generátor obsahuje nějaké vedlejší efekty nebo vstupy, nebo ne.
Co kdybych chtěl např. lazy sekvenci, která by mi vracela *aktuální* obsah souboru? Dalo by se to nějak udělat ("vypnout" cachování)?
Re: cachování výpočtů
celé vláknoNo nejjednodussi je v tomto pripade vubec nenavazovat sekvenci na zadny symbol, tj. sice pouzit defn, ale vyhnout se def - nerikam ovsem, ze je to vzdy elegantni :/
Re: cachování výpočtů
celé vláknojeste pridam zajimavou informaci, co jsem pred chvili dohledal: "Rich Hickey, the designer of Clojure, responded by saying that he had already experimented with uncached lazy sequences, and that such a choice causes a different set of problems with performance problems and code breaking – problems which he found to be even more common than the ones I've raised here."
Re: cachování výpočtů
celé vláknoTen post vypadá zajímavě, teď nemám čas/chuť to číst, ale určitě se k tomu vrátím, včetně toho vlákna v konfeře Clojure, kde tohle Hickey říká. Dost by mě totiž zajímalo, čím tohle tvrzení podkládá.
Autor postu má argumenty (imho) silný a logický, přesně tohle mě právě napadlo taky:
First, it's easier to convert an uncached sequence to a cached sequence than vice versa. Second, if you forget to cache something that should be cached, it's merely a performance optimization problem, but if you forget to uncache something that needs to be cached, your program can crash. So, it's safer if the language defaults to uncached.
Přijde mi, že by bylo lepší použít uncached sekvence a k tomu cacheovací wrapper, který by programátor mohl a nemusel použít, podle vlastního uvážení.
Re: cachování výpočtů
celé vláknoTo je pravda, taky me napadlo, proc tam neni nejaky wrapper, budu muset Hickeyho taky prostudovat - on ma totiz opravdu zajimave nazory, takze nektere "nedostatky" Clojure jsou ve skutecnosti prednostmi, kdyz k tomu poda patricne vysvetleni.
Re: cachování výpočtů
celé vláknoBohužel, ale o tom to právě je. Vedlejší efekty by se (nejen) tady používat neměly a jsou IMHO jen trpěné...
Re: cachování výpočtů
celé vláknoS vedlejšími efekty není problém, pokud jsou pod kontrolou typového systému.
fce apply je zajimava
celé vláknoChtel bych podekovat za krasny serial. Closure se mi nesmirne libi.
Jenom bych se chtel ujistit, ze chapu dobre pouziti fce apply. Pokud apply predam pouze dva parametry (tzn. fce a "ten posledni"), bude zavolana fce s "rozbalenym" poslednim parametrem (predpokladam, ze se rozbaluje pouze jedna uroven). Tzn.
(apply fce [d [e] f])
je zrejme chybne v pripade, ze fce neumi pracovat s vektory. Toto mi tedy umoznuje na misto posledniho parametru predat lazy sekvenci (tzn. v dobe kompilace neznamy pocet prvku). Pokud vsak znam nektere parametry jiz v dobe kompilace, mohu je zapsat jeste pred tim poslednim parametrem. Tyto se vsak jiz nebudou "rozbalovat". Je to tak?
(apply fce nerozbali take_nerozbali [tohle rozbali])
Re: fce apply je zajimava
celé vláknoAno, je to tak, pro apply je dulezity pouze jeji prvni parametr (vlastni funkce) a posledni parametr (obecne lazy sekvence a samozrejme vsechno specialnejsiho, napriklad vektor, seznam...). Ty parametry "mezi" jsou tam proto, ze nektere funkce proste vyzaduji vetsi pocet parametru, nejenom jednu rozbalenou sekvenci. Nejjednodussi priklad je prave scitani, tam se ale moc nepozna, jak to vlastne funguje - co se quotuje a co rozbaluje:
user=> (apply + [1 2 3]) 6 user=> (apply + '(1 2 3)) 6 user=> (apply + 1 2 3 '(1 2 3)) 12
To je ovsem jednoduche, zajimavejsi je napriklad toto pouziti:
(map
(fn
[x]
(apply max x))
'( [1 2 3] [4 5 6] [7 8 9]))
(3 6 9)
.....
celé vláknoNie je nic lahsie ako si to overit :)
Staci ist na http://tryclj.com a zadat napr.:
(apply println [1 [2] 3])
(apply println [1] [2] [3])
Re: .....
celé vláknoPravda :) Mne teda v Opere ten webovy interpret nechodi (mam zakazane predavani klavesoych eventu pro javascript) a po ruce jsem zrovna clojure nemel. Ale nyni mam a je to skutecne tak, jak jsem to pochopil :).
Mimochodem println se chova take zajimave - nedoporucuji ji pred prectenim dokumentace/ozkousenim pouzivat.
Re: .....
celé vláknoI bez zakazu JS (nebo jeho casti) to v Opere chodi nejak divne - kdyz je text vetsi nez okno te konzole, tak se pri zapisu porad skace na zacatek a hned zase na konec (jakoby to napred fokusovalo prvni radek a hned potom radek s kurzorem).
Na druhou stranu ma clojure-1.4.0-slim.jar velikost nejakych 850 kB, coz je dneska zanedbatelne (kdysi zhruba polovina kapacity diskety :))), tak to taham s sebou na USB disku - co kdyby

