lambdaniel

Daniel Janus o języku, typografii, książkach, programowaniu w Clojure i nie tylko

Praktyczne użycie monady state

Wreszcie rozumiem monady!

Pierwszy raz zetknąłem się z nimi dobrych osiem lat temu, przy okazji nauki Haskella; wtedy jednak nie starczyło mi cierpliwości, aby zaznajomić się z podstawami teoretycznymi. Sprawy nie ułatwiał fakt, że trudno o naprawdę przystępne i zrozumiałe wprowadzenie do tego tematu: wygląda na to, że każdy adept Haskella, zrozumiawszy monady, pisze na ten temat własny tutorial. Ja się powstrzymam od tego naturalnego odruchu i po prostu odeślę do niesamowicie szczegółowego, ośmioczęściowego cyklu artykułów autorstwa Mike'a Vaniera, który — wreszcie! — sprawił, że coś mi “zaskoczyło” w umyśle. Zamiast tego w tym wpisie wynotuję najważniejsze spostrzeżenia, jakie zapamiętałem, a potem pokażę dwie wersje pewnego kodu operującego na sekwencjach bitów: niemonadyczną i napisaną z użyciem monady state.

Mike zakłada znajomość Haskella, jak pisze we wstępie, na poziomie typów polimorficznych i klas typów; w praktyce jednak myślę, że do zrozumienia tekstu wystarczy pewne obycie z haskellową notacją (bardzo zresztą przypominającą zwykłą notację matematyczną), bo bardziej zaawansowane rzeczy są wyjaśniane w tekście na bieżąco. Bardzo polecam.

Oto więc moje notatki:

  • Kluczowe dla zrozumienia monad jest pojęcie funkcji monadycznych; znacznie łatwiej jest je sobie intuicyjnie wyobrazić niż monadyczne wartości, zwracane przez m-return. Mike podaje pewne intuicje także dla tych drugich, ale dla mnie ważne jest, żeby myśleć o monadach w kategoriach (wzbogaconych) funkcji, a nie wartości przez nie zwracanych.
  • Łatwo wydefiniować przy użyciu prostego złożenia operacji m-bind i m-return funkcję składającą ze sobą dwie funkcje monadyczne. Przy użyciu tego operatora, który Mike nazywa <=<, prawa rządzące monadami wyrażają się w elegancki i prosty do zapamiętania sposób: jest to operator łączny oraz m-return jest jego lewą i prawą jedynką.
  • I bodaj najistotniejsza rzecz — nie trzeba rozumieć monad, żeby ich używać. Niby oczywiste i niby tak właśnie pisałem do tej pory kod haskellowy, radośnie używając do-notacji tak jakbym pisał kod imperatywny; ale okazuje się, że w ten sam sposób można z powodzeniem używać monady stanu i wyjaśnić, co ona robi, zupełnie w oderwaniu od całej reszty teorii monad. Wiedza na temat tego, co się dzieje “pod spodem”, jest konieczna tylko (i aż!) do zrozumienia, co poszczególne monady mają ze sobą wspólnego.

Reszta tego wpisu będzie poświęcona właśnie przykładowemu użyciu monady stanu w Clojure. Pisałem wcześniej, że nie widziałem dotąd kodu, który dałby się wyrazić przejrzyściej zapisany z użyciem monad niż bez nich — i właśnie na taki kod się natknąłem.

Wyobraźmy więc sobie, że mamy strumień bitów. Dla prostoty zdefiniujmy sobie przykładowy strumień, na którym będziemy testować nasze funkcje, jako clojurowy wektor zer i jedynek.

(def v [1 1 1 0 1 0 1 0 1 0])

Chcemy naddać naszemu strumieniowi pewne uporządkowanie: zdekodować zera i jedynki, które z niego przychodzą, według jakiegoś kodu o zmiennej długości. Najbardziej oczywistym, znanym każdemu kodem jest kod binarny: czytamy ze strumienia ileś bitów, traktujemy je jako binarną (bez znaku) reprezentację pewnej liczby i zwracamy tę liczbę. Łatwo napisać w Clojure funkcję, która to robi.

(defn read-binary [n bits]
  (loop [res 0 n n [fst & rst :as bs] bits]
    (if (zero? n)
      [res bs]
      (recur (+ res res fst) (dec n) rst))))

Spróbujmy wczytać z naszego strumienia czterobitową liczbę:

(read-binary 4 v)
;=> [14 (1 0 1 0 1 0)]

Czternaście. Ale zauważmy, że zdekodowana liczba nie jest jedyną zwracaną wartością! Żeby dało się z naszego strumienia odczytywać dalsze liczby, musimy zwrócić parę (wektor dwuelementowy): wartość odczytana plus reszta strumienia, z ktróej będziemy czytać dalej. Piszemy wszak funkcyjnie: nie zmieniamy naszych wartości w miejscu, tylko z jednych wartości produkujemy następne.

Innym rodzajem kodu jest kod unarny: czytamy po prostu ze strumienia jedynki, aż napotkamy pierwsze zero — wtedy przestajemy czytać i naszą wartością jest liczba przeczytanych bitów. W ten sposób dowolną liczbę dodatnią n da się zareprezentować na n bitach. Implementacja jest równie prosta:

(defn read-unary [bits]
  (loop [n 1 [fst & rst] bits]
    (if (zero? fst)
      [n rst]
      (recur (inc n) rst))))

Sprawdzamy:

(read-unary v)
;=> [4 (1 0 1 0 1 0)]

Trzy jedynki i zero, razem cztery skonsumowane bity, więc odczytaną liczbą jest 4. Działa.

Spróbujmy teraz skleić nasze funkcje, to znaczy odczytać ze strumienia dwie liczby: najpierw zakodowaną unarnie, a potem binarnie na sześciu bitach.

(let [[x v1] (read-unary v)
      [y v2] (read-binary 6 v1)]
  [x y])
;=> [4 42]

Wynik jest poprawny, ale kod nieelegancki: tak naprawdę nie interesują nas te wszystkie v, v1, v2, które przepychamy przez nasze funkcje; potrzebujemy tylko przeczytanych liczb, a poszczególne części strumienia są nam tylko po to, żeby mieć z czego czytać. Im więcej składanych ze sobą operacji, tym łatwiej się pomylić.

Tu wkracza monada stanu, która umożliwia ukrycie tych pośrednich wartości i bardziej eleganckie złożenie read-unary i read-binary. Monadycznie zapisalibyśmy to jakoś tak:

(domonad state-m
         [x read-unary
          y (partial read-binary 6)]
         [x y])
;=> #

Wygląda to bardzo podobnie. domonad state-m jest jak let. Tak jak chcieliśmy, nie przekazujemy naszego stanu (strumienia) explicite; zamiast tego przy x i y podajemy funkcje, które mają być zawołane na aktualnym stanie, żeby uzyskać żądaną wartość i nowy stan.

No dobrze, ale gdzie tu miejsce na nasz stan początkowy? Jak go przekazać? Proste: powyższa formuła, jak widać z mało czytelnego wyniku, zwróciła jakąś funkcję. Wystarczy ją teraz zawołać na naszym początkowym stanie, aby uzyskać wynik wraz ze stanem końcowym:

(*1 v)
;=> [[4 42] nil]

Jedyne, co wydaje się nadmiarowe w naszym złożeniu, to owo partial pojawiające się wyżej. Jest to efekt uboczny faktu, że Clojure w odróżnieniu od Haskella rozróżnia funkcje jedno- i więcejargumentowe (tak dokładniej to w Haskellu występują wyłącznie funkcje jednoargumentowe). Skoro w domonad state-m powinny na przemian pojawiać się symbole i funkcje jednoargumentowe biorące stan, to gdy nasza funkcja akceptuje coś jeszcze (tu: liczbę bitów), powinniśmy zrobić z niej funkcję jednoargumentową za pomocą partial. Alternatywnie, jeżeli chcemy trzymać się stylu monadycznego, możemy przepisać read-binary jako:

(defn read-binary [n]
  (fn [bits]
    (loop [res 0 n n [fst & rst :as bs] bits]
      (if (zero? n)
        [res bs]
        (recur (+ res res fst) (dec n) rst)))))

Teraz zamiast (partial read-binary 6) możemy napisać po prostu (read-binary 6).

Teraz, kiedy umiemy już składać operacje stanowe, zilustrujemy to przy pomocy jeszcze jednego kodu, a właściwie rodziny kodów nazywanych kodami Golomba. Po szczegółowy opis odsyłam do Wikipedii, natomiast dla potrzeb tego artykułu wystarczy nam wiedza, że te kody są parametryzowane jedną liczbą m. Liczba w kodzie Golomba jest podzielona na dwie części, z których pierwsza jest zakodowana unarnie, a druga — nie większa niż m — binarnie. W implementacji możemy więc skorzystać z naszych gotowych już funkcji read-unary i read-binary.

Bez dłuższych już komentarzy przedstawię dwie implementacje: eksplicytną i używającą monady stanu. Obie będą używać pomocniczej funkcji read-bit, czytającej po prostu jeden bit ze strumienia i używanej tak samo jak read-unary czy read-binary.

(defn read-bit [[bit & bits]]
  [bit bits])

Najpierw wersja niemonadyczna:

(defn read-golomb [m]
  (fn [bits]
    (let [k (clog2 m)
          r (- (bit-shift-left 1 k) m)
          [a bits1] (read-unary bits)
          [b bits2] ((read-binary (dec k)) bits1)
          [ir bits] (if (< b r)
                      [b bits]
                      (let [[nb bits] (read-bit bits)]
                        [(+ b b nb (- r)) bits]))]
      [(+ (* (dec a) m) ir) bits])))

A teraz używająca monad. Żeby nie przeplatać let i domonad, można po prostu zdefiniować funkcję zwracającą pewną stałą wartość i niezmieniony stan — nazwę ją m-const:

(defn m-const [x]
  (fn [state]
    [x state]))

Używając jej, możemy zaimplementować read-golomb tak:

(defn read-golomb-monadic [m]
  (domonad state-m
           [k (m-const (clog2 m))
            r (m-const (- (bit-shift-left 1 k) m))
            a read-unary
            b (read-binary (dec k))
            nb (if (< b r) (m-const nil) read-bit)]
           (+ (* (dec a) m)
              (if (< b r) b (+ b b nb (- r))))))

Czytelniej?

Posted on 2012-01-10

Spóźniony post na Blog Day 2011

Przegapiłem tegoroczny Dzień Blogów. Ale kto powiedział, że notka zawierająca odnośniki do pięciu lubianych i czytanych przeze mnie blogów nie ma prawa pojawić się kilka dni po kanonicznej dacie? Oto więc one:

  • Notatnik zapisywany wieczorami: na tej liście teoretycznie nie powinno być blogów z “mojej branży” czyli okołoinformatycznych, ale nie mogę tu nie umieścić odnośnika do zapisków Marcina Kasperskiego. Bo też nie są one stricte techniczne (z ostatnich miesięcy przychodzi mi na myśl świetna notka o autorytetach), a są dla mnie wzorem: setki wpisów, a każdy obszerny, wartościowy i zawierający oryginalne przemyślenia lub cenną syntezę wiedzy. Marcin nie stara się zaskarbić sobie czytelników akcjami marketingowymi i nie dba specjalnie o rozgłos. Po prostu robi swoje: pisze ciekawie. Bardzo, bardzo bym chciał, żeby takich blogów było więcej.
  • Migotanie słów: Polski matematyk w Brazylii: o kulturze, o historii, o brazylijskich doświadczeniach i, jakże by inaczej, o matematyce. Jeśli miałbym określić ten blog jednym przymiotnikiem, byłoby to słowo “mądry”. Dziękuję, Andrzeju.
  • Widziane z okna na strychu: Można by powiedzieć, że to blog feministyczny, ale to bardzo spłycające określenie. Jak dotąd, siedem wpisów. Ale jakich! Już pierwszy ujął mnie stylem i roztropnością – chciałbym umieć pisać takim językiem i z takim wyczuciem o trudnych sprawach.
  • Haderech, czyli droga: O ilu miejscach w sieci mogę powiedzieć “pamiętam, jak tu trafiłem”? O tym tak, choć od roku nie jest już aktualizowane. Szukałem, skąd się wziął tekst “Who By Fire” Cohena — jak się okazuje, jest on zaczerpnięty z Unetane Tokef, dwunastowiecznej hebrajskiej modlitwy. Bardzo ciekawe studium odkrywania własnej tożsamości i odkrywania starodawnej ścieżki. Polecam i podziwiam.
  • Złote myśli Piotra S.: zanim Twitter stał się, ten blog już był. Trudno mi oddać jego specyfikę, polecam po prostu zajrzenie i doświadczenie specyficznego humoru autora :–)

I na zakończenie ciekawostka liczbowa: trzy z opisywanych blogów prowadzone są w serwisie Blox, a dwa używają autorskich silników. Go figure.

Posted on 2011-09-05

MazUNIX Dąbrowskiego

Jeszcze Polska nie zginęła,    $ (ps ax | grep Polska) 
póki my żyjemy.                  && (ps ax | grep `whoami`)
Co nam obca przemoc wzięła,    $ sudo chown -R / `whoami`
szablą odbierzemy.
  Marsz, marsz, Dąbrowski,     $ ./Dabrowski 
  z ziemi włoskiej do Polski.    </dev/ziemia-wloska >/dev/polska
  Za twoim przewodem           $ ifconfig eth0 up
  złączym się z narodem.       $ telnet polska.pl
Posted on 2011-07-24

ClojureScript

Rich Hickey, autor Clojure, wyrasta na Steve'a Jobsa nowoczesnych języków programowania — przynajmniej jeśli idzie o sposób prezentacji swoich dzieł. Oto kilka dni temu na grupie dyskusyjnej Clojure pojawiło się ogłoszenie, że Rich wystąpi na najbliższym spotkaniu nowojorskiej grupy użytkowników Clojure, że strumień wideo z wystąpienia będzie nadawany na żywo i że zaprezentowane zostanie “coś nowego”.

Tym czymś okazał się ClojureScript: kompilator Clojure do JavaScriptu, łączący moc pierwszego języka z powszechnością drugiego.

JavaScript bywa nazywany “czarnym koniem” języków programowania, najbardziej niedocenianym językiem minionej dekady i najważniejszym obecnej. Istotnie, silniki JavaScriptu w przeglądarkach — a także wolnostojące, jak Node.js — poczyniły w ostatnich latach kolosalne postępy, jeśli chodzi o wydajność, narzędzie to jest coraz chętniej używane do programowania coraz poważniejszych aplikacji i nie mijając się z prawdą można powiedzieć, że JavaScript jest wszędzie.

A teraz te same słowa można odnieść również do Clojure. W tegorocznym sondażu, podobnie jak rok temu, społeczność Clojure najczęściej wskazywała JavaScript jako hipotetyczną alternatywną wobec JVM platformę, ale zapewne mało kto się spodziewał, że urzeczywistni się to tak szybko. Łatwo sobie uzmysłowić możliwości, jakie daje nowa implementacja. Ten sam kod na serwerze i w przeglądarce? Programowanie aplikacji iOS w Clojure? Jak najbardziej!

W ramach dodawania łyżki dziegciu do tej beczki miodu trzeba zauważyć jednak, że dialekt ClojureScript jest okrojony i ma nieco inną semantykę niż standardowy Clojure: nie ma STM, niezmienność struktur danych nie jest wymuszana, wektory są zwykłymi JavaScriptowymi tablicami. Czy to się zmieni, pokaże przyszłość.

Jaka przyszłość czeka Clojure i ClojureScript? Spróbuję pokusić się o przepowiednię:

  • Pojawienie się alternatywnej wobec JVM platformy wymusi ukształtowanie się bogatszej niż do tej pory biblioteki standardowej Clojure, wspólnej dla obu wersji. Ten proces trwa już teraz: tam, gdzie w czasach Clojure 1.0 pisało się (.toUpperCase "foo") (wychodząc z założenia where Java isn’t broken, Clojure doesn’t fix it), teraz kanoniczną formą jest (clojure.string/upper-case "foo"). W ten sposób Clojure stopniowo stanie się językiem niezabawkowym według definicji Maćka Pasternackiego.
  • ClojureScript otworzy dla Clojure zupełnie nową niszę: stanie się popularny wśród programistów-frontendowców, piszących do tej pory głównie w JavaScripcie lub CoffeeScripcie.
  • Równocześnie pojawienie się ClojureScript nie oznacza, że zatrzymają się prace nad “tradycyjnym” Clojure. JVM pozostanie główną platformą rozwoju języka i to tam będą pojawiać się kolejne innowacyjne cechy. Wersja 1.3 jest już w fazie beta i nadanie jej statusu final jest kwestią kilku tygodni.

Patrząc wstecz, aż trudno uwierzyć, jak dużą popularność zdobyło sobie Clojure. Gdyby ktoś mi cztery lata temu powiedział, że za cztery lata pojawi się nowy język z rodziny Lisp, który będzie znacznie bardziej elegancki niż Common Lisp, znacznie praktyczniejszy niż Scheme i używać go będą wielkie instytucje finansowe, wyśmiałbym go. A jednak: zaczynam wierzyć, że prawo Kopernika jednak nie stosuje się w informatyce.

Posted on 2011-07-21

Jeszcze o matematyce w szkole

Zaczęło się od listu maturzystki opublikowanego przez Gazetę Wyborczą, zawierającego narzekanie na temat obowiązkowości matury z matematyki. Rozpętała się burza: przez Internet przetoczyła się fala krytyki, w większości odsądzającej autorkę od czci i wiary. Moja własna reakcja była nieco bardziej stonowana; parę dni temu odkryłem, że została również opublikowana przez Wyborczą razem z innymi opiniami.

A dziś, szukając zupełnie czego innego, natknąłem się przypadkiem na ten artykuł Paula Lockharta. I zgadzam się z absolutnie każdym słowem; w swoim liście próbowałem powiedzieć mniej więcej to samo, ale nie potrafiłem ująć tego ani w jednej dziesiątej tak dobrze.

Przeczytajcie ten artykuł. Teraz. Uważam, że jest lekturą obowiązkową dla obu stron barykady: i antytalentów matematycznych, i ludzi twardo broniących matury z matematyki w jej obecnym kształcie.

Posted on 2011-07-17

Informatyka jest gałęzią matematyki

Claygirl pisze na blogu GeekGirls, że wbrew powszechnemu mniemaniu, informatyka to nie matematyka — i że informatykowi znajomość matematyki jest potrzebna w bardzo ograniczonym zakresie. Zdziwiłem się, bo jestem odmiennego zdania i zawsze wydawało mi się, że to właśnie pogląd, że informatyka jest częścią matematyki, jest w mniejszości… Zapewne jednak większość klepaczy kodu rzadko zadaje sobie to pytanie. Szkoda, bo warto stawiać fundamentalne pytania o to, czym w istocie jest to, czym się zajmujemy.

Temat jest mi bliski, postaram się więc w tym wpisie uzasadnić swoją opinię. Żeby móc sensownie odpowiedzieć na nasze pytanie, powinniśmy wpierw zdefiniować, co rozumiemy przez informatykę, a co przez matematykę. Zaczniemy więc od definicji encyklopedycznych.

Wikipedia dixit

Informatyka — dyscyplina naukowa i techniczna zajmująca się przetwarzaniem informacji, a w tym technologiami przetwarzania informacji oraz technologiami wytwarzania systemów przetwarzających informacje.

Myślę, że większość z nas zgodziłaby się z takim opisem. Aplikacje webowe, bazy danych, systemy operacyjne… czymkolwiek się zajmujemy, zawsze ma to związek z przetwarzaniem informacji. A matematyka?

(Zanim zajrzymy do Wikipedii, zachęcam do pokuszenia się o własną definicję. Może to przyprawić o ból głowy, bo jak objąć kilkoma słowami całe to bogactwo abstrakcyjnych bytów, jakimi matematyka się zajmuje? Liczby, zbiory, klasy, relacje, funkcje, punkty, przestrzenie, formuły, kategorie…)

Matematyka — nauka dostarczająca narzędzi do otrzymywania ścisłych wniosków z przyjętych założeń, zatem dotycząca prawidłowości rozumowania.

Ścisłość rozumowania i abstrakcje

Ta definicja w ogóle prześlizguje się nad owym bogactwem; jest szersza, bardziej pierwotna i może budzić sprzeciw. Zdaje się sugerować, że ilekroć myślimy o czymś — czymkolwiek — w sposób uporządkowany, zajmujemy się matematyką! A jednak wielu matematyków uważa, że to właśnie w myśleniu tkwi sedno ich dziedziny. Włodek Holsztyński ujmuje to w swoim świetnym eseju jeszcze zwięźlej:

Matematyka jest sztuką myślenia

Gdzie jednak przy takim podejściu postawić granicę pomiędzy matematyką a innymi naukami? Czy fizyka jest częścią matematyki, czy odrębną dziedziną wiedzy, która tylko korzysta z metod matematycznych? Wspominałem wcześniej o bytach abstrakcyjnych: wszyscy mamy mniej więcej zbliżone pojęcie na temat tego, czym jest liczba 7, mimo że taki obiekt nie istnieje fizycznie w otaczającym nas świecie. Wydaje się, że abstrakcyjność jest wpisana w naturę matematyki, i można ją dopisać do definicji. Wspomniany artykuł w Wikipedii zawiera inne próby zdefiniowania tej dziedziny przez sławnych matematyków, z których kilku o tym wspomina. Dirac: “Matematyka jest narzędziem stworzonym specjalnie do wszelkich abstrakcyjnych koncepcji, i nie ma ograniczeń dla jej potęgi w tym zakresie”.

A Poincaré mówi: “sztuka nadawania takich samych nazw różnym rzeczom”. Innymi słowy, zdolność dostrzegania podobieństw i abstrahowania od różnic. To jabłko jest czymś innym niż tamta gruszka, ale mają ze sobą coś wspólnego: liczność — tak zapewne brzmiało pierwsze, doniosłe odkrycie matematyczne.

Matematyka w szkole

…jest tylko drobnym wycinkiem wszystkich tych działów. To oczywiste, w końcu poświęca się jej ograniczoną ilość czasu. Ale za duży nacisk kładzie się na ich przedstawienie, a za mały na rozumienie. Nie jest ważne, żeby wiedzieć, ile jest siedem razy dziewięć. Ważne, żeby umieć w razie potrzeby się zastanowić i dojść do prawidłowej odpowiedzi. Rzadko pokazuje się dowody twierdzeń (i potem uczniowie panicznie boją się słowa “udowodnij”), a szkoda! Nie jest trudno zobaczyć, dlaczego twierdzenie Pitagorasa jest prawdziwe, albo dlaczego mnożenie liczb naturalnych jest przemienne. A tak właśnie ćwiczy się umiejętność myślenia.

A informatyka?

Clay pisze:

Ale całe dziesiątki poziomów abstrakcji wyżej siedzą sobie systemy operacyjne i maszyny wirtualne z którymi większość informatyków widuje się najczęściej. Informatyków – programistów języków wysokopoziomowych (takich jak Java, C#, Ruby, Python etc), którzy z matematyką muszą się znać tylko po to, żeby umieć myśleć logicznie i na przykład oszacować czas działania napisanego właśnie programu.

Już samo słowo “poziomy abstrakcji” kojarzy się z tym, o czym pisałem wcześniej. Oto mój program, mam w nim jakąś klasę.

public class Osoba {
    String imie, nazwisko;
    int wiek;
}

Ona modeluje jakiś obiekt rzeczywisty, ale sama w sobie jest równie abstrakcyjnym bytem jak liczba 7. Jest napisana w języku Java — mogę sięgnąć po formalny opis jego gramatyki i semantyki i ściśle opisać, czym jest. I wreszcie, pisząc taki kod, pomyślałem o tym, co poszczególne osoby mają wspólnego i abstrahowałem od nieistotnych dla mnie różnic między nimi.

Czy nie tym właśnie zajmuje się matematyka? W jaki sposób mój program albo język programowania jest mniej obiektem matematycznym, niż trójkąt albo zbiór {4, 42}?

Nie we wszystkim jesteśmy dobrzy

Pomijając terminologię, trzeba się zgodzić z tezą artykułu Clay: fakt, że nie czujemy się mocni w jednej gałęzi matematyki (nazwijmy ją “licealną”), wcale nie musi oznaczać, że nie rozwiniemy skrzydeł w innej. Nikt nie jest omnibusem, nierozumienie czegoś nie jest powodem do wstydu. Srinivasa Ramanujan, bodaj największy geniusz matematyczny ubiegłego stulecia, wniósł gigantyczny wkład do teorii liczb i wielu innych dziedzin… ale nie miał zielonego pojęcia, co to jest funkcja zmiennej zespolonej!

Tak i my nie musimy tego wiedzieć, pisząc kod czy grzebiąc w bebechach systemu. Miejmy jednak świadomość, że w istocie uprawiamy matematykę, która jest sztuką myślenia — i cieszmy się tym.

Posted on 2011-05-07

Wrażenia z java4people 2011

Jest niedzielny poranek, siedzę w pociągu relacji Szczecin-Warszawa i właśnie wyciągnąłem laptopa, aby spisać wrażenia z trzeciej edycji konferencji java4people, która odbyła się wczoraj w Szczecinie, póki jeszcze nie okrzepły i nie rozmyły się.

Zanim opowiem o poszczególnych wystąpieniach, winienem oddać zasłużone gratulacje organizatorom, czyli szczecińskiemu JUG-owi. Przestronne, nowoczesne aule Zachodniopomorskiego Uniwersytetu Technologicznego, dostępne przez cały czas ciastka i herbata, obiad (załapałem się na dokładkę!), after-party, a nade wszystko ciekawe prezentacje i rozmowy kuluarowe — wszystko to stwarzało znakomitą atmosferę sprzyjającą temu, aby posłuchać o nowych językach i technologiach wokół Javy i JVM oraz “dzielić się wiedzą i pasją”, jak głosi motto konferencji. Wielkie brawa!

Jedyny niedosyt polegał na tym, że prezentacje poprowadzone były w dwóch równoległych blokach, a do tego w trzecim bloku trwały warsztaty z SWT/JFace. Momentami bardzo doskwierał mi brak możliwości bilokacji, ale trudno winić o to organizatorów.

Oficjalnego otwarcia dokonał prof. Antoni Wiliński, dziekan Wydziału Informatyki ZUT, życząc uczestnikom owocnej wymiany doświadczeń. Następnie część ludzi udała się posłuchać wystąpienia Tomka Kopacza o .NET i Javie, ja zaś zadebiutowałem w roli prelegenta na imprezie tego formatu, opowiadając o Clojure.

Trudno mi wypowiadać się o własnej prezentacji — nie jestem dobrym mówcą i to było widać. Jak się jednak okazało z rozmów ze słuchaczami, udało się zainteresować część osób tematem. Sukces jest więc połowiczny, a postaram się, aby następnym razem było lepiej. Slajdy można znaleźć tu.

Potem wybrałem się na wystąpienie Przemka Pokrywki o Scali. Scala bywa wymieniana jednym tchem z Clojure, gdy mowa o nowych językach funkcyjnych działających na JVM, więc byłem bardzo ciekaw tego wykładu. I nie zawiodłem się: z Przemka wprost emanowała pasja, znać było też dużą wiedzę i doświadczenie w temacie. Przemek ciekawie pokazał, w jaki sposób Scala łączy paradygmat funkcyjny z obiektowym — w tym drugim zakresie przypomina mi Smalltalka: tu też wszystko jest obiektem i 2 + 3 oznacza zawołanie na obiekcie 2 metody + z parametrem 3. Fajnym mechanizmem wydaje się też możliwość definiowania własnych niejawnych konwersji — to sposób na wzbogacanie już istniejących klas o nowe funkcjonalności, ale bez zmiany tych klas; przypomina to trochę Clojurowe protokoły i extend-type. Dopisuję do listy rzeczy do wypróbowania.

Po obiedzie, zachęcony tytułem, wybrałem się na prezentację “Skalowalność technologii Javowych w zastosowaniach komercyjnych” Dawida Gruszczyńskiego. Organizatorzy konferencji na samym początku rozdali ankiety, w których prosili o ocenienie każdego wystąpienia w skali od 1 (szkoda czasu) do 5 (naprawdę warto) — po tej prezentacji dały się słyszeć rozmowy, że należałoby dać jej 0 albo i -1. Ja jestem łagodniejszy w swych ocenach. Bezsprzecznie prezentacja była źle zatytułowana: tytuł obiecywał opowieść o technikach czy narzędziach projektowania skalowalnych aplikacji; tymczasem okazało się to klasycznym success story dotyczącym systemu obsługi spisu powszechnego, w tym oprogramowania działającego na terminalach używanych przez rachmistrzów.

Czy ta prezentacja była nie na miejscu na takiej konferencji? Może i tak. Mam jednak słabość do success stories i duży szacunek do ludzi, którym udaje się stworzyć działające, niezawodne oprogramowanie, nawet jeśli nie zgadzam się z wyborem technologii. To naprawdę spora rzecz. A samej prelekcji trzeba oddać, że była sprawnie przeprowadzona, slajdy zrozumiałe, a diagramy prezentujące architekturę systemu — czytelne. Wątpliwości słuchaczy budziła kwestia bezpieczeństwa transmisji danych (i samych rachmistrzów!) Ciekawostka: terminale rachmistrzowskie mają zmienne IP, ale nie powiadamiają serwera co chwila o swoim aktualnym adresie, bo wywoływałoby to zanadto duże obciążenie. Co więc robi terminal, gdy zmieni mu się adres? Otóż… wysyła SMS (!) ze swoim aktualnym adresem!

Na wystąpieniu Sebastiana Pietrowskiego o Jythonie (a także samym Pythonie i Django) nie dowiedziałem się wiele nowego, z racji wcześniejszych swoich doświadczeń z Pythonem. Ale też celem tej prezentacji było chyba nie tyle przekazanie wiedzy, co podzielenie się własnymi doświadczeniami, z subiektywnego punktu widzenia — i to udało się Sebastianowi znakomicie. Stąd slajdy zatytułowane “What I Like”, “What I Don’t Like”, “What I’d Use Python For” — bardzo pragmatyczne. Sebastian opowiadał między innymi o tym, że Jythona można fajnie wykorzystać jako narzędzie do eksploracji nowych API z REPL-a: używając pythonowej introspekcji można łatwo obejrzeć listę pól i metod udostępnianych przez dowolną klasę. W swoim wystąpieniu o tym nie opowiadałem, ale w pakiecie repl-utils w Clojure Contrib jest funkcja show, która daje bardzo podobny efekt.

Słuchając wystąpienia Bartka Kuczyńskiego o Vaadinie utwierdziłem się w przekonaniu, że nie chcę pisać aplikacji webowych tak jak okienkowe, na modłę swingową. Vaadin ma w zamierzeniu służyć właśnie do tego: to nadbudowany nad GWT modularny framework WWW. Bartek pokazywał dziejącą się pod spodem magię, wraz z protokołem, którym część kliencka kompilowana do JS komunikuje się z serwerową (UIDL — dobrze pamiętam? — i JSON z danymi do wyświetlenia, poprzedzonymi ni mniej ni więcej tylko pętlą nieskończoną for(;;);, co podobno ma jakiś sens). Psikus w tym, że ostatnio w Smyrnie zrobiłem dokładnie odwrotną rzecz, to znaczy napisałem aplikację desktopową tak jakbym pisał webową, a więc używając ajaksowego XML-RPC (odsyłam do niedawnego postu na ten temat), i wyszło na oko prościej niż w Vaadinie. Może opowiem o tym na Warszawa JUG?

Nie zdążyłem się obejrzeć, a to już koniec konferencji! Do dotychczasowych bonusów dołączył kolejny: wśród wypełniających ankiety organizatorzy rozlosowali pięć książek. Los wytypował mnie jeszcze raz i schowałem do plecaka “Domain-Specific Languages” Martina Fowlera.

Pokonferencyjne after-parties bywają bodaj ważniejszymi nawet elementami takich spotkań niż same prezentacje. To tam toczy się najwięcej rozmów, to tam zawiązują się nowe znajomości i trwają nieskrępowane, długie dyskusje. Tak bywa z pizzą na Auli, tak było i teraz. Wielkie dzięki raz jeszcze organizatorom, wszystkim, których poznałem, z którymi udało mi się porozmawiać, i tym, którzy przebrnęli przez moje wystąpienie. Do zobaczenia przy innej okazji!

Posted on 2011-04-19

Nadchodzi Wayland

Podczas jednego z ostatnich surfathlonów rzuciła mi się w oczy informacja o nowym kawałku uniksowego oprogramowania. Rozwijany bez wielkiego rozgłosu i dziś niemal nieznany, za kilka lat prawdopodobnie będzie jednym z kluczowych elementów absolutnie każdego biurkowego Linuksa. Mowa o serwerze wyświetlania Wayland, który ma wielką szansę stać się sensowną alternatywą dla X Window System.

X-y mają jedną kluczową zaletę. To wielki kawał oprogramowania bardzo intensywnie testowanego od dziesiątków lat, który działa. A jednak ilekroć uruchamiam ps ax lub top i widzę działający na moim komputerze, zżerający kilka procent czasu procesora i kilkanaście procent pamięci serwer X, mierzi mnie, gdy pomyślę, co tam się dzieje pod spodem.

X Window System narodził się jako protokół wyświetlania, pomyślany z wielkim rozmachem na początku lat 80. tak, aby w pełni wykorzystać moc ówczesnych stacji roboczych z wielkimi, monochromatycznymi wyświetlaczami. Bezstanowy model wyświetlania X jest już na starcie bardzo skomplikowany. Żeby zrobić coś tak prostego jak narysowanie kreski na ekranie, trzeba kolejno: otworzyć połączenie do serwera X; utworzyć okienko; zamapować je; utworzyć maskę notyfikacji; zaczekać na zdarzenie powiadamiające, że można rysować; wywołać właściwą funkcję rysującą kreskę; wyczyścić bufor połączenia (jak to opisuje ten tutorial). System czcionek bitmapowych, wiele sposobów określania współrzędnych ekranowych, wielki zestaw prymitywów graficznych, biblioteki Athena czy Xt — wszystko to jest bagażem historycznym, z którego współczesne oprogramowanie już nie korzysta, a mimo to każdy Linux przychodzi z całym tym dobrodziejstwem inwentarza. Dwa wzajemnie niekompatybilne podsystemy renderowania tekstu? Taka jest rzeczywistość. A próbowaliście kiedyś zapanować nad tym w czystym C? Powodzenia.

Do tego X przez lata obrastał w sadełko w postaci różnych rozszerzeń protokołu, jak XRandR czy XRENDER, potrzebnych do jako takiego sensownego działania. Współczesne pulpity z bajeranckimi efektami jak falujące okna czy choćby półprzezroczyste terminale nie byłyby bez nich możliwe.

Przezroczystość sieciowa, powiadacie? Tak, ale spróbujcie zdalnie uruchomić glxgears albo pograć w Quake'a po sesji X. Nawet Firefox, gdy go uruchamiam przez ssh -X po szybkim łączu na serwerze oddalonym o kilka kilometrów od domu, ślimaczy się i jest nieużywalny. Kwestię zdalnego uruchamiania aplikacji graficznych znacznie lepiej rozwiązał Microsoft ze swoim Remote Desktop.

Wayland ma szansę uprościć cały okołoiksowy bałagan. Jest napisany tak, by mógł wykorzystać sterowniki dla nowych kart graficznych, już istniejące dla X.org. Ma bardzo prosty model wyświetlania: to nie sam serwer wyświetla grafikę, ale po prostu udostępnia klientom swoje bufory. Współczesne biblioteki, jak Cairo, GTK+ czy Qt, już potrafią z niego korzystać. Chciałoby się powiedzieć: nareszcie!

Z niecierpliwością czekam dnia, w którym na żadnej z moich linuksowych maszyn nie będzie działał żaden serwer X.

Posted on 2011-03-14

Przeczytane: Sen elektryka (Wiesław Myśliwski, "Traktat o łuskaniu fasoli")

Mówi się czasem, że zapamiętujemy wszystko, co rejestrują nasze zmysły. Nawet jeśli wydaje się, że jakieś mało z pozoru znaczące zdarzenie z przeszłości odeszło w zapomnienie — bywa, że ni stąd ni zowąd przypominamy je sobie pod wpływem nowych zmysłowych doznań albo skojarzeń. I właśnie czegoś takiego ostatnio doświadczyłem, odłożywszy na półkę właśnie przeczytany “Traktat o łuskaniu fasoli” Wiesława Myśliwskiego.

To było jakieś cztery, może pięć lat temu; siedziałem wtedy w którymś ze stołecznych Sphinxów, jedząc obiad. Między jednym a drugim kęsem moje uszy wychwyciły znaną melodię, której zdecydowanie nie spodziewałem się usłyszeć w radiu “pod kotleta”. Pink Floyd. Który utwór Floydów może puszczać popularna rozgłośnia? “Money”? “Another Brick In The Wall, Part II”? Może od wielkiego dzwonu “Wish You Were Here”? Nie, to był utwór z jednego z najposępniejszych, najmniej podkotletowo wtapiających się w tło albumów (a przy okazji mojego ulubionego). “The Gunner’s Dream” z płyty “The Final Cut”.

Jest taki moment w tym utworze, kiedy przeciągłe “…and hold on to the dream” Watersa zanika przechodząc w długie solo saksofonowe. I właśnie wtedy usłyszałem ten saksofon inaczej. Do tej pory wydawało mi się, że harmonijnie współbrzmi z resztą, teraz jednak wybijał się, skrzeczał, zaznaczał się niespokojnym dysonansem. Mniej miło, ale może bardziej pasująco do nastroju utworu. Niepokój, niejasne wrażenie czegoś utraconego, co już nie istnieje. Ot, szybko wietrzejąca emocja, ale w uśpieniu przetrwała lata.

I obudziła się z ostatnią stroną “Traktatu…”.

Blurb na okładce mówi o “drążeniu Tajemnicy”, o “nieszukaniu łatwych rozwiązań”, o “metafizyce”. Może tak, ale nie to zapamiętam. Zwłaszcza że sama fabuła nie jest zawiła: oto u starszego pana zjawia się przybysz poszukujący fasoli do kupienia; fasolę ma ów pan tylko niełuskaną, więc zaprasza nieznajomego do domu i podczas całodziennego wspólnego łuskania snuje monolog – opowieść o sobie. O wspomnieniach z dzieciństwa, o rzece i lampie naftowej. O strasznych doświadczeniach wojny. O trudnych powojennych czasach odbudowy. O ciężkiej pracy elektryka i, tak, tak, o saksofonach. A także o kapeluszach i psach. Jest ten monolog bardzo naturalny i pozbawiony śladu pretensjonalności (i w tym tkwi jego siła: przywodzi mi na myśl równie mocne i proste “Requiem” Achmatowej), a mimo to zmusza do myślenia i zadawania pytań.

Jeśli przyjąć definicję prozy Włodka Holsztyńskiego (parafrazuję: proza to taki tekst literacki, w którym autor podaje 90% obrazu, zostawiając czytelnikowi zbudowanie sobie pozostałych 10%; ta definicja stawia prozę w opozycji do poezji, w której ta proporcja jest pół na pół — te procenty są oczywiście umowne, ale dają pewne wyobrażenie o roli czytelnika), to na tej skali “Traktat…” sytuuje się gdzieś pomiędzy. Bo jest niedopowiedziany, bo budzi wątpliwości, bo pozwala zajrzeć do niedookreślonego świata, który nie jest moim światem.

Ale podoba mi się. Bardzo polecam.

Posted on 2011-02-28

Janusowie z Dęblina?

Pisze do mnie Nan Cain z Florissant, Missouri (cytuję w tłumaczeniu):

Mój dziadek, Walenty Janus, urodził się w Polsce w roku 1890. Przybył do Stanów Zjednoczonych w młodym wieku, osiadł w stanie Michigan i ożenił się z Sophie Hojnacki. Próbuję dowiedzieć się czegoś więcej o jego rodzinie (być może jego ojciec miał na imię Franciszka [sic!]). W dokumentach imigracyjnych jako miejscowość pochodzenia figuruje Giblin, ale nie mogę znaleźć miejscowości w Polsce o tej nazwie.

Niewiele mi to mówi. Janus to dość popularne nazwisko; na stronie Marka Futregi widzę, że nosi je około 10 tys. osób w Polsce i akurat wśród znanych mi Janusów nie było żadnego Walentego, który by wyemigrował do USA. Wydaje mi się, że “Giblin” może być amerykańsko-fonetycznym zapisem Dęblina — tak mógł usłyszeć oficer imigracyjny i tak zapisać.

A publikuję ten post w nadziei, że może ktoś z czytelników tego bloga wie coś o Walentym i mógłby podzielić się informacją. Będę wdzięczny za wiadomość (najlepiej w komentarzach do niniejszego wpisu).

Posted on 2011-02-13