Od dzisiejszego wieczoru, kanał @learnclojure na twitterze przeszedł pod opiekę autora książki "The Joy of Clojure". Książka niebawem pojawi się w sprzedaży, a dzięki uprzejmości wydawnictwa Manning, mam ją przyjemność czytać od kilku tygodni i szczerze cierpię z powodu nadmiaru informacji, których nie mogę w żaden sposób strawić w tempie, jakim bym sobie życzył - powiedzmy, zamiast tradycyjnego 5 x 45 minut tygodniowo nauki Clojure (jak to miało miejsce za czasów szkolnych z chociażby matematyką), zamarzyło mi się podwoić to. I boli, bo zintensyfikowanie wysiłków przy nauce Clojure (przez m.in. zwiększenie czasu dla niego), wcale nie przekłada się na zwiększenie przyswajania wiedzy o nim w strawnej postaci. Czuję, że zaczynam wykorzystywać te miejsca w moim umyśle, które do tej pory były rezerwowane na pogrywanie sobie w Civilization, albo Traviana :-)
Jeśli ktoś nie wierzy, że nauka języka programowania może boleć i chciałby poczuć klimaty, w których przychodzi zmagać się z "oczywistościami" dla osób, które pojęły już te tajniki (jak ma miejsce często przy rozmowach o Javie w moim przypadku, kiedy to nie mogę zrozumieć, że Java może być i jest dla wielu trudna), niech przyjrzy się poniższej konstrukcji (zaczerpnięte z dzisiejszego statusu na kanale @learnclojure) i odpowie na pytanie: "Co będzie wynikiem wykonania?".
user=> (->> (iterate inc (int \a)) (take 26) (map char)) ;...jaki będzie wynik? user=> (map char (range (int \a) (int \{))) ;...wynik jak wyżej i pytanie to samoSzacunek dla tego, komu tego typu cudeńka nie sprawiają problemu. Ja, kiedykolwiek widzę podobne konstrukcje, zwijam się z bólu, a głowa eksploduje. Pora trawić.
W ramach uzupełnienia, trochę dokumentacji, która może pomóc w zrozumieniu powyższego.
user=> (doc ->>) ------------------------- clojure.core/->> ([x form] [x form & more]) Macro Threads the expr through the forms. Inserts x as the last item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the last item in second form, etc. nil user=> (doc iterate) ------------------------- clojure.core/iterate ([f x]) Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects nil user=> (doc inc) ------------------------- clojure.core/inc ([x]) Returns a number one greater than num. nil user=> (doc int) ------------------------- clojure.core/int ([x]) Coerce to int nil user=> (doc take) ------------------------- clojure.core/take ([n coll]) Returns a lazy sequence of the first n items in coll, or all items if there are fewer than n. nil user=> (doc map) ------------------------- clojure.core/map ([f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls]) Returns a lazy sequence consisting of the result of applying f to the set of first items of each coll, followed by applying f to the set of second items in each coll, until any one of the colls is exhausted. Any remaining items in other colls are ignored. Function f should accept number-of-colls arguments. nil user=> (doc char) ------------------------- clojure.core/char ([x]) Coerce to char nil user=> (doc range) ------------------------- clojure.core/range ([] [end] [start end] [start end step]) Returns a lazy seq of nums from start (inclusive) to end (exclusive), by step, where start defaults to 0, step to 1, and end to infinity. nil
Odpowiem enigmatycznie: wynikiem w obu przypadkach będzie to samo, co wynikiem
OdpowiedzUsuń(seq "abcdefghijklmnopqrstuvwxyz")
;-)
Osobiście, przy pierwszym spojrzeniu, czytelniejszy jest dla mnie drugi zapis (z map) - uzyskanie literału znakowego dla odpowiednich liczb. Zrozumienie makra ->> przychodzi z czasem...
OdpowiedzUsuńTeż myślałem, że ->> jest trudne, ale kiedy wiadomo, że wcześniejsze jest drugim parametrem aktualnego, to w zasadzie sprawa się upraszcza. Mimo wszystko zawsze pozostaje pytanie, czy to tylko uproszczenie ala DSL, a ostatecznie będzie tak samo szybko jak w Javie z 200 liniami (specjalnie wyolbrzymiłem z tymi liniami) i gdzie się ta wiedza może przydać. Wciaż borykam się z tym problemem.
OdpowiedzUsuńJedną z zalet już sam wymieniłeś. Po co spędzać czas nad konstrukcją pętli i if-ów, skoro można ten sam problem zapisać w sposób szybki i zgrabny za pomocą programowania funkcyjnego i makr. Przynajmniej takie jest moje zdanie.
OdpowiedzUsuń