28 października 2010

monad w Clojure ciąg dalszy - o ich wewnętrznej reprezentacji

0 komentarzy
Logo ClojureZaczniemy od podniesienia wersji Clojure i Clojure Contrib w naszym środowisku. Nie ma ku temu żadnego, praktycznego powodu, a jedynie poznawanie nowego przez jego użytkowanie (w ten sposób można nawet nie zorientować się, że znamy nowe, bo po prostu było, to się używało). Pamiętamy o ciągłej nauce, samodoskonaleniu, ku uciesze członków zespołu? :-)

Wersja Clojure 1.3.0-alpha2 dostępna jest na jego stronie domowej (sekcja Downloads).

Podniesienie wersji Clojure nie wystarczy do korzystania z monad (w wersji 1.2).
devmac:~ jacek$ clj
Clojure 1.3.0-alpha2
user=> (use 'clojure.contrib.monads)
CompilerException java.lang.ClassNotFoundException: clojure.set, compiling:(clojure/contrib/accumulators.clj:121)
Konieczne jest pobranie standalone-1.3.0-alpha2.jar (z repo clojure.contrib) i umieszczenie w CLASSPATH dla Clojure REPL. Od tej chwili można cieszyć się dobrodziejstwem inwentarza.

Oczywiście w projektach zalecane jest skorzystanie z narzędzia w stylu Apache Maven, np. dla Clojure byłby nim Leiningen, a później należy postępować zgodnie z clojure-contrib 1.3.0-alpha2 deployed to build.clojure.org.

Po tych zmianach uruchamiamy REPL i wczytujemy przestrzeń c.c.monads, w której definiowane są monady.
devmac:~ jacek$ clj
Clojure 1.3.0-alpha2
user=> (use 'clojure.contrib.monads)
nil
Rozgrzewkę mamy za sobą.

Wracając do tematu przewodniego, tym razem nie będzie, do czego służą monady programistom czy matematykom, ale jak się je definiuje w Clojure i czym są w tym języku (ich wewnętrzną reprezentacją). Mam nieodparte wrażenie, że wiele zostało powiedziane o monadach i ten obszar został już dostatecznie zagospodarowany (zainteresowanym polecam przeczytać artykuły, które mam za sobą nt. monad ze znacznikiem "monads" na delicious.com).

Już wiemy (patrz poprzednie wpisy w kategorii clojure), że matematycznie i praktycznie monada to trójka składająca się z konstruktora typu - obliczenia, z którym związane są dwie, obowiązkowe funkcje - w terminologii Clojure będą to m-bind i m-result.

Poznawanie monad w Clojure opieram w dużej mierze na czytaniu artykułów, ale zauważam postęp w zrozumieniu ich sensu, kiedy poza materiałem literackim, uzupełniam go o przegląd źródeł c.c.monads z ich testami (dostępne w repo Gita - clojure-contrib/modules/monads).

Makro monad

Pierwsza konstrukcja tworzenia monad w Clojure to makro monad, które definiuje monadę jako mapę nazw funkcji i ich implementacji (coś ala klasa w Javie). W monadzie-mapie znajdziemy wskazanie na dwie, obowiązkowe funkcje m-result i m-bind oraz opcjonalne m-zero i m-plus.
user=> (monad
[m-result identity
 m-bind (fn [mv f] (f mv))
])
{:m-plus :clojure.contrib.monads/undefined, :m-zero :clojure.contrib.monads/undefined, :m-bind #<user$eval919$m_bind__920 user$eval919$m_bind__920@45570f5c>, :m-result #<core$identity clojure.core$identity@20773d03>}
W ten sposób zdefiniowaliśmy monadę. Tylko, co można z nią zrobić? Nic. W Javie mogłoby to odpowiadać konstrukcji new PewnaKlasa() bez przypisania jej do zmiennej (nie wliczając skutków ubocznych, co jest możliwe, ale nierekomendowane, np. wykonanie statycznej metody, albo stworzenie wątku). W Clojure nie ma zmiennych (to jest koncept języka imperatywnego), a jedynie symbole (koncept języka funkcyjnego).

Innymi słowy, monada w Clojure jest niczym innym jak mapą składającą się z nazw funkcji w postaci kluczy :m-plus, :m-zero, :m-bind i :m-result z ich implementacją (jeśli podana na wejściu).

Dobrze byłoby przypisać nazwę takiej strukturze, np. za pomocą (def nazwa (monad ...)).
user=> (def moja-monada (monad 
 [m-result identity
  m-bind (fn [mv f] (f mv))
  ]))
#'user/moja-monada
user=> moja-monada
{:m-plus :clojure.contrib.monads/undefined, :m-zero :clojure.contrib.monads/undefined, :m-bind #<user$fn__923$m_bind__924 user$fn__923$m_bind__924@54c707c1>, :m-result #<core$identity clojure.core$identity@20773d03>}
user=> (type moja-monada)
clojure.lang.PersistentArrayMap
c.c.monads dostarcza już takiego makro - defmonad.
user=> (doc defmonad)
-------------------------
clojure.contrib.monads/defmonad
([name doc-string operations] [name operations])
Macro
  Define a named monad by defining the monad operations. The definitions
    are written like bindings to the monad operations m-bind and
    m-result (required) and m-zero and m-plus (optional).
nil
user=> (defmonad moja-monada-2 
 [m-result identity
  m-bind (fn [mv f] (f mv))
  ])
#'user/moja-monada-2
user=> moja-monada-2
{:m-plus :clojure.contrib.monads/undefined, :m-zero :clojure.contrib.monads/undefined, :m-bind #<user$fn__927$m_bind__928 user$fn__927$m_bind__928@67b14530>, :m-result #<core$identity clojure.core$identity@20773d03>}

Makro with-monad

Kolejnym makro w c.c.monads jest with-monad. Dzięki niemu operacja monadyczna zostaje związana z konkretną implementacją w danej monadzie.

Weźmy za przykład monady: maybe-m, sequence-m oraz state-m. Każda z nich musi dostarczać dwie metody - m-bind oraz m-result. Każda z nich musi działać na z góry ustalonej strukturze obliczeniowej. Zobaczmy.
user=> (with-monad maybe-m (m-result 1))
1
user=> (with-monad sequence-m (m-result 1))
(1)
user=> (with-monad state-m (m-result 1))
#<monads$fn__774$m_result_state__775$fn__776 clojure.contrib.monads$fn__774$m_result_state__775$fn__776@65cb048e>
W przypadku funkcji m-result jej wynikiem jest zwrócenie wartości monadycznej dla podanej na wejściu - dla maybe-m będzie to po prostu podana wartość, sequence-m zwróci listę jednoelementową z podaną wartością, a state-m zwróci funkcję, która na wejściu wymaga podania stanu (środowiska, w którym będzie działało ciało funkcji "stanowej") i w wyniku jej wykonania dostaniemy parę - wartość, która została podana na wejściu m-result oraz aktualny stan (nim może być cokolwiek i najczęściej jest kolejna mapa z przypisaniami symbol - wartość, jak zmienne w Javie). Sprawdźmy.
user=> (def f-stanowa (with-monad state-m (m-result 1)))
#'user/f-stanowa
user=> (f-stanowa 5)
[1 5]
user=> (f-stanowa {:a 5 :b 7})
[1 {:a 5, :b 7}]
I teraz najlepsze: gdyby sobie wyobrazić (a może po prostu przypomnieć), że każdy program (w dowolnym języku) wykonuje się na pewnym stanie, który moglibyśmy reprezentować jako mapę - zmienna-wartość, to z monadą state-m możemy wykonać program napisany w języku funkcyjnym bez pojęcia stanu, emulując stan monadą. Tworzymy środowisko - stan początkowy - i każde wykonanie funkcji w jego ramach będzie dotyczyło jedynie tego stanu. Zamiast przekazywać stan z funkcji do funkcji (przez ich szeregowanie) można skorzystać z monady state-m i zjąć sobie ten kłopot z barków, wykonując funkcje tak, jakby ten stan po prostu był. Zdecydowanie upraszcza testowanie i zrównoleglanie obliczeń, bo zakłada się, że funkcje nie mają skutków ubocznych i działają w zamkniętej przestrzeni. To było dla mnie niezwykle odkrywcze w swojej prostocie.

Wystarczy tych pieśni na dzisiaj. Jutro kolejna porcja moich znalezisk monadycznych. Pytania i uwagi mile widziane. Jako podsumowanie można oczekiwać prezentacji na Warszawa JUG. Ach, następne będzie 9. listopada z Cezarym Bartoszukiem, który przedstawi temat "Przegląd języków programowania i ich funkcjonalności".

27 października 2010

Geronimo, JMX i Groovy

3 komentarzy
Apache GeronimoDostałem zadanie rozpracowania dostępnych obiektów Java Management Extension (JMX) - MBeans - w serwerze aplikacyjnym Apache Geronimo. Osoba zlecająca potrzebowała monitorować Geronimo i kiedy dowiedziałem się o tym, od razu zaproponowałem wykorzystanie JMX. W końcu, po to ta technologia została stworzona.

I przyszło mi stworzyć klienta ("Trzeba było się nie wychylać", ktoś mógłby krzyknąć).

Przeglądając różne materiały dotyczące JMX API, brakowało mi spójnego przykładu. Natchnęło mnie, aby napisać własnego. Chwila namysłu i padło na...Groovy. W końcu do tego typu zadań świetnie się nadaje.

(Gdyby nie fakt, że poszukiwanie rozwiązania trwało i musiałem sobie przypomnieć programowanie w Groovy, zacząłbym od...) Po chwili miałem działające rozwiązanie w groovysh.
import javax.management.ObjectName
import javax.management.remote.JMXConnectorFactory as JmxFactory
import javax.management.remote.JMXConnector as JmxConn
import javax.management.remote.JMXServiceURL as JmxUrl

serverUrl = 'service:jmx:rmi://localhost/jndi/rmi://localhost:1099/JMXConnector'

url = new JmxUrl(serverUrl)
creds = ["system", "manager"] as String[]
env = ["jmx.remote.credentials":creds]
jmxc = JmxFactory.connect(url, env)

server = jmxc.MBeanServerConnection;

for (d in server.domains) { println d }

mbeanName = "geronimo:J2EEServer=geronimo,name=JVM,j2eeType=JVM"
mbean = new ObjectName(mbeanName)

println server.getAttribute(mbean, "kernelBootTime")

jmxc.close();
Trzeba jeszcze skrypcik lekko podrasować, aby użyć produkcyjnie, ale ogólny zarys już jest. Usprawnienia mile widziane.

Mam nieodparte wrażenie, że zastosowałem właściwe narzędzie do problemu. A jak Ty podszedłbyś/podeszłabyś do tematu?

p.s. Podczas rozpoczęcia konferencji warsjawa 2010 pozwoliłem sobie zrobić dygresję, taki drobny żarcik, odnośnie kobiet na sali, kiedy to na moje pytanie - już nie pamiętam jakie - padła odpowiedź damskim głosem. Natychmiast przypomniałem sobie skecz z Monty Pythona - Stoning i ledwo udało mi się utrzymać powagę. Skecz bajka! Że też zawsze musi mnie "natchnąć" w trakcie publicznych wystąpień (!)

26 października 2010

Krótko o clojure.test

3 komentarzy
Logo ClojureZaczęło się od lektury Testing Clojure Code – Awesome “are”. Przypomniałem sobie, że jednym z pytań w trakcie mojego wykładu o Clojure podczas 70. spotkaniu Warszawa JUG było "Jak testować kod napisany w Clojure?" Wiemy, że Clojure kompilowany jest do bajtkodu, więc to, testujemy w Javie jest do wykorzystania z Clojure.

Jednak dla mnie pytanie wskazywało raczej potrzebę zrozumienia, jak to jest testować aplikacje Clojure w Clojure. Trafiłem na clojure.contrib.test-is, gdzie znalazłem informację, że teraz Clojure oferuje clojure.test.

Sprawdźmy, jak to działa. Krótko.
devmac:~ jacek$ clj
Clojure 1.2.0
user=> (use 'clojure.test)
nil
user=> ; Czy 5 == 4?
user=> (is (= 5 (+ 2 2)))

FAIL in clojure.lang.PersistentList$EmptyList@1 (NO_SOURCE_FILE:5)
expected: (= 5 (+ 2 2))
  actual: (not (= 5 4))
false
user=> ; Test mianowany "Crazy arithmetic"
user=> (is (= 5 (+ 2 2)) "Crazy arithmetic")

FAIL in clojure.lang.PersistentList$EmptyList@1 (NO_SOURCE_FILE:6)
Crazy arithmetic
expected: (= 5 (+ 2 2))
  actual: (not (= 5 4))
false
user=> ; Można również definiować zestawy testowe makrem deftest
user=> (deftest addition
  (is (= 4 (+ 2 2)))
  (is (= 7 (+ 3 4))))
#'user/addition
user=> ; ...i je uruchamiać funkcją run-tests
user=> (run-tests)

Testing user

Ran 1 tests containing 2 assertions.
0 failures, 0 errors.
{:type :summary, :test 1, :pass 2, :fail 0, :error 0}
Można też uruchomić testy z innej przestrzeni nazewniczej (aka pakietach w Clojure). W ten sposób oddzielamy sam test od testowanego kodu.
user=> ; Definiujemy nową przestrzeń testy
user=> (ns testy)
nil
testy=> (use 'clojure.test)
nil
testy=> ; W niej definiujemy zestaw testowy makrem deftest
testy=> (deftest addition
  (is (= 7 (+ 3 4))))
#'testy/addition
testy=> ; Zmieniamy aktualną przestrzeń
testy=> (ns user)
nil
user=> ; Wykonujemy testy z innej przestrzeni
user=> (run-tests 'testy)

Testing testy

Ran 1 tests containing 1 assertions.
0 failures, 0 errors.
{:type :summary, :test 1, :pass 1, :fail 0, :error 0}
p.s. Wczoraj wyszła wersja Clojure 1.3 Alpha 2, ale poza tym, że jest i podobno jest ciekawa, nic więcej :)

23 października 2010

warsjawa 2010 za nami - o Javarsovii 2011 już myślimy

3 komentarzy
Przygotowania do konferencji warsjawa 2010 trwały około 3 tygodnie. Wśród organizatorów znalazły się następujące osoby: Bartek Zdanowski, Marcin Zajączkowski, Łukasz Lenart oraz Jacek Laskowski. Każdy zabrał się za swoją działkę, ale i tak większość decyzji podejmowana była wspólnie (zdaje się, że mimo pełnej samodzielności, każdy z nas czuł się w obowiązku zrelacjonować postępy, aby pozostali mogli śmiało powiedzieć, że wiedzą, co się chociażby ogólnie dzieje).

Uruchomienie rejestracji uzmysłowiło nam, że istnieje niemałe zapotrzebowanie na tego typu inicjatywy. Po kilku dniach "dobiliśmy" do poziomu konferencji z 214 zarejestrowanymi uczestnikami. To przerosło szacunki każdego z nas, organizatorów. Kiedy pomyślę sobie, że początkowo planowałem warsjawę na poziomie 100 osób, a 150 traktowałem jako marzenie, a nie cel, pojawia mi się lekkie powątpiewanie w możliwości mojego szacowania możliwości "objętościowych" na przyszłoroczną Javarsovię 2011. Aż strach pomyśleć, o jakich liczbach możemy myśleć w aspekcie uczestników oraz sponsorów i ich wsparcia finansowego.

A skoro o tym, to warsjawa 2010 uzmysłowiła mi rosnące poparcie firm informatycznych dla inicjatyw Warszawa JUG. Jeszcze przy Javarsovia 2010, to my odpytywaliśmy sponsorów o udział w konferencji. Tym razem było zauważalnie inaczej. Wielu ze sponsorów kontaktowało się z nami. Najpierw Altkom, później SoftwareMill, Pragmatists, CoCoNet, Accenture i ej-technologies. MIMUW jako patron użyczył nam swoich sal, co na samym początku zagwarantowało sukces przedsięwzięcia. Rozmowa ze sponsorami zwykle kończyła się przy pierwszej iteracji, gdzie padały nasze możliwości i potrzeby, a sponsor przystawał na nie. Bajka.

Tym samym chciałbym podziękować wszystkim sponsorom za ich udział w warsjawie 2010. Bez Was nie byłoby takiej oprawy konferencyjnej.

Konferencja zaczęła się wystąpieniem Wojtka Erbetowskiego, później wystąpił Paweł Lipiński, Dariusz Łuksza, Marcin Rzewucki z Janem Rychterem, Adam Michalik i Rafał Rusin. Z każdej prezentacji wyniosłem coś wartościowego - czy to ze względu na sposób prezentacji (tutaj moim faworytem stał się Jan Rychter z 30-minutowym przedstawieniem Clojure okiem praktyka!) oraz merytorycznie (tutaj wskazałbym na wstęp Darka Łukszy o EGicie oraz prezentacja Adama Michalika z bajtkodem). Szkoda jeszcze, że tak niewielu z nas czuje potrzebę podzielenia się swoimi doświadczeniami zawodowymi podczas konferencji. Pamiętam, że wcale nie było pewne, czy uda nam się ostatecznie zebrać 6 prelegentów. Doświadczenie prezenterskie to umiejętność, którą idzie wyćwiczyć, ale jak ze wszystkim, trzeba próbować i "platforma" Warszawa JUG jest doskonałym miejscem. Za 1,5 tygodnia kolejne spotkanie i wystarczy się zgłosić w roli prelegenta. Ot, takie to proste.

W trakcie prezentacji, szczęśliwa 30-tka miała możliwość uczestniczenia w szkoleniu z pisania wtyczek do Eclipse, prowadzonym przez Krzysztofa Daniela z poznańskiego IBM Eclipse Support Center. Udało mi się jedynie posłuchać początku i odniosłem wrażenie, że będzie słodko (dosłownie w postaci rozdawanych batonów jako nagroda za poprawną odpowiedź i w przenośni).

Uczestnicy nie zawiedli. Już od rana można było mówić o około 100 uczestnikach i widać było żywo prowadzone dyskusje. Miałem okazję porozmawiać z osobami ze Szczecina, Lublina, Krakowa, Radomia, Płocka i oczywiście Warszawy (ciekawym, jakiego miasta nie wymieniłem?!) U wszystkich zauważyć można było chęć organizowania spotkań, czy to w ramach JUGów, czy konferencji. Chętnie pomogę i wystarczy zapytać, aby dowiedzieć się, że można, nie jest to specjalnie trudne i choćby 30 osób jest warte wysiłku. Kluczem do sukcesu jest wiara w powodzenie przedsięwzięcia, a jedynie rozmiary mogą deprymować, co zdecydowanie nie powinno być przeszkodą, aby w ogóle podjąć się wysiłku. Warto, bo w krótkim czasie można dowiedzieć się więcej niż samodzielnie rozpracowując temat, a kontakty towarzystkie nie dadzą się zastąpić nawet najlepiej napisanym CV, kiedy potrzeba zmienić pracę i zaczepić się w ciekawym zespole. Później, na swoim, podobno są one wręcz niezbędne.

Na koniec konferencji rozlosowano nagrodę w postaci PlayStation3. Gratuluję wygranemu, tym bardziej, że samemu ostrzyłem sobie zęby na niego. Następnym razem.

Później, w ponad 10-osobowej grupie spotkaliśmy się w Jeff'sie. Jedzenie dobre, atmosfera pozytywna, więc można liczyć, że to nie ostatnia inicjatywa Warszawa JUG. Miło się móc spotkać bezpośrednio i omówić różne sprawy (niekoniecznie informatyczne, aczkolwiek te wyraźne nadawały ton).

Na minus konferencji trafiają niewystarczająca ilość napojów, szczególnie po pizzy oraz projektor o niskiej rozdzielczości. Nad obiema sprawami należy się pochylić przy kolejnych konferencjach, jeśli mają być zauważalnie lepsze od poprzednich.

Nagrania są i czekają na obróbkę. Wierzę, że szybko pojawią się na parleys. Kiedy? Hmmm, tego nawet najstarsi górale nie wiedzą.

Do zobaczenia na spotkaniach Warszawa JUG i Javarsovia 2011.

Relacje uczestników warsjawa 2010:

20 października 2010

Wrażenia z 70. spotkania WJUG - Clojure i ja w akcji...zaginęliśmy?

2 komentarzy
To była dopiero przeprawa - droga przez męki dla słuchających mojego wystąpienia podczas 70. spotkania Warszawa JUG.

Zaczęliśmy około 18:10 z projektorem, który komunikatem o swojej niedyspozycji (coś związanego z wentylatorem, czy innym swoim podzespołem) zajął połowę wyświetlanego slajdu, centralnie. Próbowałem udać, że nie powinno popsuć nam to spotkania.

Pamiętając moje dokonania na polu utrzymania czasu prezentacji i że wielu przykłada do tego równie wielką wagę, jak do strony merytorycznej, poprosiłem uczestników, abyśmy równo o 19:30 zakończyli spotkanie. Od tej godziny, wyjście z sali nie mogło być okraszone złowrogim spojrzeniem prowadzącego. Takie ukonstytuowaliśmy prawo. Bez względu na miejsce w mojej prezentacji, 19:30 stała się godziną graniczną chyba, że znajdą się tacy, którzy poproszą o więcej. I tacy się znaleźli! Wtedy się dopiero zaczęło bezpardonowe zmaganie z czasem. Skończyliśmy o 21:15 w sali, w gronie około 15 osób , aby kończąc dyskusje przy wejściu - tym razem już w gronie 7 osób - zakończyć całość około 21:45. W domu pojawiłem się po 22:00 (!)

Gdyby tylko liczba uczestników, dyskusje i poszczególne czasy na odcinkach - właściwa prezentacja, dyskusje po, w sali i przy wejściu, miały być wyznacznikiem sukcesu, powiedziałbym, że był ogromny. Zawsze uważam z przymiotnikami, które podobnie jak gusta, mają różne zabarwienia dla różnych ludzi, ale tym razem nic poza "ogromny" nie przychodzi mi do głowy.

Merytorycznie? Cóż, mogło być lepiej. Z mojego "prezenterskiego" punktu widzenia nie popisałem się. To znaczy, popisałem się, ale niewiedzą, a to zdecydowanie nie było tematem spotkania. O Clojure było conieco, może trochę więcej o samym programowaniu funkcyjnym i w zdecydowanej przewadze wiele o (bez?)sensowności użycia Clojure w projektach, które obecnie są przez nas obsługiwane Javą.

Tutaj sypiąc głowę popiołem, kajam się przed uczestnikami, prosząc o wybaczenie, że dałem się ponieść próbie porównywania Clojure do Javy, kiedy wcale nie byłem do tego przygotowany, a w dodatku, wcale nie miałem zamiaru tego robić (!) Języka Java zacząłem uczyć się w czasach appletów, kiedy to one były jedynym sposobem, aby ożywić strony HTMLowe. To była era wszechobecnego CGI z perlem i znajomość rozwiązania tego akronimu albo umiejętność wyjaśnienia, o co w nim chodzi znaczyły wiele (coś, co teraz porównałbym do Java EE i zasad rządzących serwerami aplikacyjnymi). Java z appletami była czymś praktycznym i w zasadzie nie było innego wyboru. Obecnie nie ma tego luksusu - nie tylko, że wybór jest między .Net a Java EE, ale mnogość rozwiązań w samej Javie - czy to języki programowania (ale tutaj można założyć, że zaleca się Javę), czy szkieletów aplikacyjnych - może przyprawić o ból głowy. Jest zauważalnie trudniej wejść nowicjuszowi w świat języka Java i Java EE. I gdzie tu miejsce dla poznawania programowania funkcyjnego i to jeszcze w wykonaniu Clojure. Ma to jakiś sens?

To nie było pytanie, na które zamierzałem odpowiedzieć i nie odpowiedziałem.

Tematem mojej prezentacji był "Wstęp do programowania funkcyjnego z Clojure". Podkreślam słowo "wstęp" i rezerwowałem sobie wręcz rozumienie go jako "wstęp do wstępu". Raczej służyło to zebraniu postrzegania nauki innego paradygmatu programowania niż imperatywno-obiektowy w wykonaniu Javy. Postarałem się o wdrożenie podejścia "Release early, release often", z tym, że tym razem chodziło nie o namacalny produkt, a wiedzę.

Jakkolwiek moja strona prezentacyjna szwankowała, to uważam, że strona przeciwna (w sensie analogicznym do pary lewa-prawa a nie za-przeciw), czyli słuchacze, spisała się wyśmienicie. Na sali znalazło się 5 osób, które na pytanie "Czy programujesz w języku funkcyjnym?" odpowiedziały "Tak" - dwie czysto hobbistycznie, jedna programująca w Clojure w Fablo.pl, inna, która właśnie przeszła (jak to ujęła) z "naukowego" Haskella na bardziej finansowo-zorientowaną Scalę i ostatnia, która swoją przygodę z programowaniem zaczęła od programowania funkcyjnego i, jak się okazało później, zna około 30 języków programowania z Javą okrzykniętą jako ten język, który nie tylko, że ma się dobrze, ale będzie wiodącym przed długie lata. Pozostała, bodajże 35-cioosobowa, grupa to programiści Java, którzy albo mieli zajęcia z programowania funkcyjnego na studiach, albo przymierzają się do języka Scala, albo kto wie, co w pozostałych głowach siedzi.

Rozmawialiśmy o wsparciu IDE dla programowania funkcyjnego w dowolnym języku - przewijał się Groovy, Scala i Clojure, naprzemiennie. I można było zauważyć ogólnie panujące przekonanie, że brak wsparcia IDE w postaci podpowiedzi, refactoringu, przeglądania hierarchii klas w górę/dół, przeskakiwania między wywołaniem funkcji, a jej definicją, w zasadzie skreśla język jako możliwy do zastosowania w projekcie komercyjnym, w którym "więcej się czyta kod niż pisze". Tego nie brałem wcześniej pod uwagę, a to kładę na karb mojego, niewielkiego udziału w projektach programistycznych. Pojawiła się teza, że przy pewnej skali projektu, można przyjąć sensowność użycia dynamicznie-typowanego języka zamiast Javy, powiedzmy przy 100k linii kodu (wartość wyjęta z kapelusza, ale ma być dostatecznie mała, aby dało się to ogarnąć). Mieszanie składniowe języków na JVM, np. Java i Clojure, w projekcie nie zdobyło entuzjazmu, przede wszystkim dlatego, że późniejsze utrzymanie może znacząco podnieść koszty. Sensowne rozumowanie, z którym trudno się nie zgodzić.

Zaprezentowałem Clojure z mojego, javowego punktu widzenia, który pozwala mi tworzyć rozwiązania Java EE z aplikacjami webowymi w roli głównej. Tutaj Java ma się świetnie i jakkolwiek mamy do dyspozycji Grails z Groovy, Lift ze Scala, Ruby on Rails z JRuby, to nie zauważyłem akceptacji wśród uczestników dla ich powszechnego stosowania, przede wszystkim z powodu obecnego stanu wsparcia narzędziowego i późniejszego utrzymywania mieszanki składniowej Java-nieJava. Uknęliśmy wręcz termin "podejście dogmatyczne", któremu przyświeca minimalizowanie języków na JVM ze wskazaniem na Javę.

Gdybym ja był słuchaczem, nie dostrzegłbym sensu nauki programowania funkcyjnego, a już tym bardziej Clojure.

Podczas mojego wystąpienia o Clojure nie pokazałem niestety nic, co nie byłoby możliwe w Javie i Java EE, a biorąc wsparcie narzędziowe i ogólny stan świadomości programistycznej o nich, to, wespół z moim prawie zerowym teoretycznym, a zerowym, praktycznym doświadczeniem, takie podejście nie miało racji zaistnienia. Za dużo jeszcze we mnie myślenia javowego, a za mało Clojure i PF. Kiedy dodać do tego brak prezentacji chociażby Clojure STM i tak podkreślanej prostoty zrównoleglania zadań w językach funkcyjnych, rozumowanie, że da się zrobić w Clojure, to, co potrafimy i robimy na codzień w Javie jest dalece niewystarczająca. Jest niewystarczające również, aby myśleć o nauce, której nie towarzyszy przeświadczenie, albo chociaż nadzieja na możliwe, przyszłe użycie praktyczne. Pełna zgoda i tutaj upatruję swoje braki. Chociażby Clojure STM jest rozwiązaniem do użycia z poziomu Javy, jako biblioteka i tu właśnie widziałbym sens prezentacji Clojure jako wzbogacenia naszego przybornika programisty. To da się użyć natychmiast. Później dopiero widziałbym ewangelizację Clojure przez pryzmat zrównoleglania, a w kolejnych odsłonach i tylko przy założeniu, że poprzednie są zrozumiałe, a być może i wykorzystywane, wchodziłbym w temat innej składni i samego programowania funkcyjnego w ogólności. To jest moja nauka na przyszłość, która wyznacza dalsze kierunki rozwoju w Clojure.

Z pozostałych tematów, które uczestnicy wyrazili jako wartościowe do pokazania w ramach naszych spotkań Warszawa JUG pojawiły się: testowanie, refactoring, wykorzystanie skryptu jako klasy, jak efektywny jest bajtkod Clojure, monady z przykładami, TCO w rekurencjach na przykładzie chociażby ciągu Fibonacciego i równoległe rysowanie kółek. Ze swej strony dodam do tego: demonstracja siły przeładowywania definicji funkcji w locie, w trakcie tworzenia oprogramowania, bez konieczności restartu środowiska uruchomieniowego oraz możliwość poznawania API Javy z użyciem Clojure REPL.

Tym samym chciałbym podziękować wszystkim uczestnikom za udział w mojej prezentacji Clojure i towarzyszące temu, niezwykle inspirujące dyskusje. Dziękuję również za cierpliwość podczas lektury tego wpisu. Ryzykuję, że zabrzmię banalnie, ale współpraca z Wami to czysta przyjemność dająca mi wiele satysfakcji. Pewnie już zwyczajowo, ale wciąż z serca, wszystkim życzę podobnych doznań.

Prezentacja dostępna jest do pobrania jako JacekLaskowski-WJUG-Wstep-PF-Clojure-19.10.2010.pdf.

Jeśli przychodzi Wam do głowy temat warty omówienia podczas spotkań JUGowych, piszcie. Ustawiam się w roli zdającego relację z postępu moich prac podczas kolejnych spotkań. Wy przywdziewacie szaty zlecających i jednocześnie egzaminujących wyniki. Czyż to nie idealny sposób na naukę dla obu stron?! "Ucząc się uczę", albo "Ucząc uczę się". Nie wierzę, że nie znajdzie się ochotnik, aby skorzystać z oferty.

Kolejne spotkanie za 2 tygodnie. Chętni? W przypadku braku, zakładam, że oddaje mi się pola na rzecz dalszego przedstawiania wad i zalet programowania funkcyjnego z Clojure. Z góry dziękuję i rezerwuję sobie prawo, do skorzystania jedynie w ostateczności.

p.s. Do warsjawy 2010 pozostały 3 dni. Do tej pory zarejestrowało się już ponad 150 osób (dokładnie 151 - stan na godzinę 11:00)! Skala zainteresowania sobotnią konferencją przeszła najśmielsze oczekiwania organizatorów. Niech będzie ona równie wartościowa dla prelegentów, jak moje wczorajsze wystąpienie dla mnie, a uczestników proszę o podobny poziom aktywności. Parafrazując słowa Owsiaka "Oj, będzie się działo!"

19 października 2010

warsjawa 2010 w nadchodzącą sobotę, 23.10 o 10:00 na MIMUW, Warszawa

0 komentarzy
Nadchodząca sobota, 23.10 przyniesie mnóstwo atrakcji około-JVM-owych, bo w gmachu Wydziału Matematyki, Informatyki i Mechaniki Uniwersytetu Warszawskiego (MIMUW) odbędzie się 3. edycja konferencji-warsztatów warsjawa 2010 organizowana przez członków Warszawa JUG w składzie: Łukasz Lenart, Bartek Zdanowski, Marcin Zajączkowski, Jacek Laskowski.

Informacje dot. harmonogramu można znaleźć na stronie konferencji, a dla wciąż nieprzekonanych wspomnę jedynie, że będzie PlayFramework, Clojure, DDD, Apache HISE, Apache Camel, bajtkod i Eclipse z EGit. Nie sądzę, aby ktokolwiek zajmujący się Javą miał problemy ze znalezieniem czegoś dla siebie (proszę o kontakt, gdybym się mylił, w co, w tym konkretnym przypadku, szczerze wątpię).

Udział w konferencji jest bezpłatny i nie wymaga bytności od jej rozpoczęcia, godz. 10:00, aż do jej zakończenia, godz. 18:00. Jeśli gwarancja dobrych wystąpień nie jest wystarczającym powodem, aby skorzystać z "oferty", to może wsparcie naszych sponsorów nakłoni Cię do zmiany decyzji?

Do tej pory udział sponsorski zgłosiły firmy: Altkom Software & Consulting, Pragmatists, SoftwareMill oraz CoCoNet. Dzięki nim możemy zaoferować wyżywienie, napoje i inne atrakcje, jak rozlosowanie PlayStation3. Wciąż mało interesująca oferta?

Co powiedział(a)byś na możliwość wymienienia się doświadczeniami z innymi praktykami? Na godzinę 11:15 zarejestrowały się 94 osoby, co przy planowanych 150 osobach daje pokaźny procent sukcesu spotkania kogoś interesującego. Wiemy, że będzie załoga ze Szczecina, Lublina, Krakowa, pewnie z innych miast, więc warsjawę 2010 można śmiało okrzyknąć konferencją ogólnopolską. Kto by pomyślał.

Zarejestruj się już teraz!

Zarejestruj się na warsjawa 2010 w Warszawie, Polska

p.s. Współpraca z firmami informatycznymi przy organizacji konferencji Warszawa JUG - Javarsovia oraz warsjawa - zaczyna sprawiać przyjemność.

18 października 2010

70. spotkanie Warszawa JUG - Jacek Laskowski z "Wstęp do programowania funkcyjnego z Clojure"

0 komentarzy
Warszawska Grupa Użytkowników Technologii Java (Warszawa JUG)Warszawska Grupa Użytkowników Javy (Warszawa JUG) zaprasza na 70. spotkanie, które odbędzie się w najbliższy wtorek, 19. października o godzinie 18:00 w sali 5440 Wydziału MIM UW przy ul. Banacha 2 w Warszawie.

Temat: Wstęp do programowania funkcyjnego z Clojure
Prelegent: Jacek Laskowski

Po 15 latach programowania imperatywno-obiektowego w Javie postanowiłem spróbować się z programowaniem funkcyjnym. Na warsztat wziąłem język Clojure, który łączy przyjemne z pożytecznym, tj. wciąż jestem na JVM i mogę korzystać z dobrodziejstw ogromnej liczby bibliotek javowych, jednocześnie programując funkcyjnie. Ostatnie moje skromne osiągnięcia na polu zrozumienia sensu tej nauki zakończyły się kilkoma użytecznymi wynikami i postanowiłem zaprezentować je szerszej publiczności. Wiążę z tym nadzieje zaangażowania większej liczby osób w poznawanie tajników PF, zebrania wskazówek dalszego rozwoju oraz szerszego spojrzenia na potencjalne wykorzystanie Clojure i PF w projektach komercyjnych.

Czego należy oczekiwać:
* Zbudowania aplikacji webowej z możliwością dynamicznego jej rozwoju
* Uruchomionego Eclipse z wtyczką CCW (counterclockwise)
* Clojure REPL
* Niewielkiej liczby slajdów (powiedzmy 5)
* Cechy języków funkcyjnych (pobieżnie, bo słabym jeszcze merytorycznie)
* Wprowadzenia, podkreślam słowo, wprowadzenia do PF z Clojure
* Nie więcej niż 1,5h wystąpienia
* Nagranego spotkania

Czego NIE należy oczekiwać:
* odpowiedzi gdzie i jak wykorzystać Clojure z Java EE
* odpowiedzi dlaczego warto nauczyć się programowania funkcyjnego lub Clojure w szczególności
* odpowiedzi na pytanie, czym Clojure jest lepszy/gorszy (niepotrzebne skreślić) w porównaniu z innymi językami, Scalę wliczając
* i wielu innych odpowiedzi na pytania o wyższość jednego nad drugim, albo uzasadnienia mojego wyboru poznania PF i to z Clojure

Jacek Laskowski jest założycielem i liderem grupy warszawskich użytkowników Javy - Warszawa JUG. Prowadzi bloga Notatnik Projektanta Java EE, w którym chciałby przedstawiać jedynie pragmatyczne użycie Javy i pochodnych. Zawodowo w IBM jako specjalista rozwiązań z rodziny WebSphere, głównie WebSphere BPM z flagowymi produktami: IBM WebSphere Process Server i IBM WebSphere Lombardi Edition. Nadaje na falach twittera jako @jaceklaskowski.

Planowany czas prezentacji to 1,5h, po których planuje się 15-30-minutową dyskusję.

Wstęp wolny

Zapraszam w imieniu prelegenta i grupy Warszawa JUG!

14 października 2010

Nagradzać zaangażowanych podwyżką - wrażenia z Video from my presentation at Agile Warsaw Jakuba Nabrdalika

19 komentarzy
Jakub Nabrdalik w swojej prezentacji (patrz Video from my presentation at Agile Warsaw) przedstawił ciekawy sposób na motywowanie zespołu programistów do większej aktywności. Jest to zbieżne z moim, ostatnim apelem o udział w konferencji warsjawa (patrz O warsjawie i monadach w Clojure - nauka wspólnie jako sposób własnego rozwoju) i wpadłem na pomysł rozwinięcia myśli, aby nagradzać zaangażowanych podwyżką. Jeśli tylko takiej żądają gratyfikacji, dlaczego nie?!

Podczas wystąpienia Jakuba padło pytanie, albo przynajmniej pojawiła się kwestia, możliwości udźwignięcia tego pomysłu przez pracodawcę i sądzę, że moje rozważania pozwalają na opanowanie i tego. Nie jest to specjalnie odkrywcze i opiera się na założeniu, że miarą kwalifikacji pracownika jest tylko i wyłącznie jego możliwość wygenerowania zysku dla firmy przez różne formy jego aktywności.

Załóżmy model firmy (niekoniecznie informatycznej, ale podprogowo to ona będzie tłem), w której rozwój osobisty jest nagradzany podwyżką, bo większe kwalifikacje, to większe możliwości firmy do zwiększenia przychodów. Trywializując, pracownik przeczytał książkę i oczekuje podwyżki. Albo bardziej wyrafinowanie, skończył pomyślnie projekt i oczekuje podwyżki. Pytanie, kiedy taka "funkcja" osiągnie swoje maksimum i czy w ogóle takowe istnieje? Byłaby to funkcja zarobków od doświadczenia, a nie funkcja zarobków od dojrzałości firmy, aby skorzystać z wiedzy wykwalifikowanego pracownika.

Pierwszy fakt (a może jednak jedynie założenie?) jest taki, że w takim modelu funkcja jest niemalejąca, czyli co jest pewne, to stabilny poziom pensji. Raz otrzymawszy podwyżkę, do końca kontraktu, kwota się należy - czy się stoi, czy się leży.

Już nie jest faktem, czy funkcja ma swój punkt maksymalny. Właśnie, czy Ty uważasz, że kiedyś nastąpi zatrzymanie wzrostu pensji? Zapewne wielu odpowie, że tak, bo "przecież nie może być tak, że będę się ciągle kształcił i jednocześnie będzie mi rosła pensja!" Czyżby?

Ja uważam, że tak może być - rośnie nasza "siła nabywcza/rynkowa", więc rośnie jednocześnie siła firmy, w której delikwent jest zatrudniony. Proszę mieć na uwadze, że nigdy nie prowadziłem żadnej firmy, nawet jednoosobowej, oraz jedynym moim podwórkiem były amerykańskie korporacje - Lucent, HP i IBM.

Oczywiście, pensja jest jedynie materiałem, za który kupujemy inne dobra, więc czy to samochód, czy wycieczka do ciepłych krajów, wliczam to do podwyżki, za którą pracownik sam będzie mógł je kupić (odpowiednio rozkładając zakup na raty z pensji). Upraszczamy model firmy, w której nagrodą może być jedynie zwiększenie pensji.

Zastanówmy się na moment. Na początku pewnie będzie stosunkowo łatwo dla pracodawcy podwyższać pensję rok do roku, bo startujemy z niskiego pułapu i margines zysków firmy z naszego zatrudnienia jest duży. Stąd tak wiele firm zatrudnia kilku wysokowykwalifikowanych pracowników, a reszta to nowicjusze, najczęściej studenci (ciekawe, czy ktoś wie, gdzie uknuto powiedzenie "Każdego specjalistę da się zastąpić skończoną liczbą studentów"?) Czy zysk firmy z naszego zatrudnienia musi maleć? Nie. Musimy jednak rozważyć coś więcej niż samo czytanie książek, np. wspomniany przed momentem mentoring.

Jakie możliwe aktywności możemy rozważyć w naszej branży? Weźmy coś, co nie kojarzy się wprost z zyskiem finansowym - czytanie książek i pisanie recenzji, które publikujemy na blogu. Doświadczyłem tego nie raz i muszę przyznać, że to niełatwe przedsięwzięcie. Stąd łatwiej będzie mi go rozłożyć na czynniki pierwsze.

Po pierwsze, należy znaleźć czas, który pracownik poświęci na przeczytanie książki. To jest jego czas prywatny. W naszym modelu firma pokrywa koszt poświęconego czasu pracownika przez 8 godzin. I właśnie za tę formę aktywności firma miałaby mu zapłacić. Dlaczego? Właśnie dlatego, że robi to w wolnym czasie, który mógłby przeznaczyć na cokolwiek innego, a nie coś, co może przynieść zysk firmie przez podniesienie jego kwalifikacji. O tym zysku za moment.

Po drugie, należy znaleźć czas na spisanie własnych przemyśleń nt. książki w postaci recenzji. To znowu jest czas prywatny pracownika. Jeśli dołożymy do tego język angielski, to może okazać sie to dla wielu na prawdę niemałym wyzwaniem - nie tylko język, ale i umiejętność spisania w nim swoim myśli. Pamiętam, jak dziś, kiedy z języka polskiego zawsze miałem 3 z wypracowań i tylko dlatego zdałem maturę z polaka, że znałem wszystkie wymagane lektury i napisałem na temat bez błędów ortograficznych...3 strony A4! Dowiedziałem się, że pisałem konkretnie do bólu i ledwo mi się udało. Teraz z pisaniem jest łatwiej, ale wciąż wyrażenie swoich myśli w angielskim uważam za niebagatelną umiejętność. To znów podniesienie kwalifikacji pracownika i zwiększa jego obszar pozyskiwania wiedzy, nie wspominając już o znajdowaniu czytelników swojego "produktu" za granicą. To niemały kapitał dla firmy. Jeszcze do tego wrócimy.

Po trzecie, blog. Prywatny, bez wzmianki o pracodawcy ma inny wydźwięk niż ten ze wzmianką, albo wręcz firmowy. Tu możemy budować kapitał firmy przez aktywność pojedynczego pracownika w obszarze jej reklamy. W końcu, wielu z nas może wymienić firmy, z którymi chciałby współpracować tylko dlatego, że jej pracownicy są rozpoznawalni w tłumie. Z naszymi, lokalnymi firmami jeszcze kiepsko w temacie reklamy własnej przez pryzmat aktywności jej pracowników, ale da się zauważyć kilka, o których mógłbym powiedzieć niemało, tylko dzięki tego typu aktywnościom - przez pryzmat ich bytności na konferencjach, twitterze czy blogach. I znowu, aktywność pojedynczego pracownika jest w ramach własnego czasu, często ze zrzeczeniem się potencjalnych "zysków" z opublikowania swojej pracy - recenzji - na blogu firmowym. Rozpoznanie pojedynczego pracownika wtedy gaśnie na rzecz budowania marki firmy. To kolejny zysk pracodawcy.

Widać, że na tym przykładzie można wyróżnić zysk pracownika - własny rozwój literacki, rozbudowanie znajomości j. angielskiego, umiejętność prezentacji własnych myśli oraz zysk pracodawcy - podniesienie kwalifikacji pracownika oraz niebagatelna sprawa - reklama. Widzę w tym wzrost obu.

Rozważmy sytuację brzegową - jesteśmy na poziomie seniorskim (a może senioralnym?) i nasza pensja oscyluje w granicach 300k PLN netto jako programista. Uśmiech na twarzach wielu, zdradza nierealność tej sytuacji w Polsce, ale wierzę, że kiedyś będzie to możliwe (a może już jest?!). Trochę przekolorowałem (i śpieszę donieść, że daleko mi do tej kwoty, usprawiedliwiając jej brak, że jest mi po prostu niepotrzebna :)), ale mimo wszystko stawiam tezę, że bez względu na poziom aktualnych zarobków, firma wciąż ma możliwość podnoszenia pensji. Jak?

Czy pracownik jest jednostką w firmie, czy pracuje zespołowo? Odpowiedź nasuwa się sama - zespół przede wszystkim. Takie myślenie mi pasuje. Idźmy dalej.

Czy w pojedynkę można zarobić 300k PLN będąc na stanowisku programisty? Hmmm, być może. Zmieni się jednak nasze myślenie, jeśli rozważymy pracę całej ekipy mniej zaawansowanych programistów, sprzedawców i innych wspierających naszą pracę pracowników. Wszyscy robią rzetelnie, jak w jednym zespole. I tu się kryje tajemnica sukcesu - "wszyscy pracują rzetelnie"! W końcu, dlaczego prezes przedsiębiorstwa może tyle zarabiać, a pracownik niższego szczebla już nie? Czy wyższy szczebel w hierarchi firmy musi wiązać się z wyższą pensją niż podwładnego? Twierdzę, że nie.

Wszystko zależy od zaangażowania. Jeśli założymy, że wszystkim zależy na dobrobycie firmy, ale nie wszystkim zależy na zarabianiu więcej i więcej, to w końcu dojdziemy do sytuacji, że firma wykształci taką kadrę pracowniczą, że będzie trywialnym zdobywać kolejne projekty w kraju i za granicą, za które pokryje koszta własnych pracowników.

Czyż to nie pracownicy przynoszą kontrakty, za które oni sami są opłacani? Cudów nie ma. Czy grasz w pojedynkę, czy w zespole, moc przerobowa zależy od Twoich kwalifikacji i zaangażowania. Na moment zapominamy o takich anomaliach, jak łapówki, kontrakty z niekwalifikowanymi zespołami, itp. To z definicji są anomalie i raczej blokują rozwój społeczeństwa i krzewią złe przyzwyczajenia, jak "Tylko znajomości są ścieżką kariery w firmie i dadzą Ci podwyżkę".

Stawiam tezę, że w pewnym momencie firma będzie dostawała coraz bardziej intratne projekty, albo pracownik utworzy firmę potomną i mając wystarczająco doświadczenia spowoduje jej utrzymanie na rynku przez naukę nowych adeptów sztuki programowania. On sam, albo ona sama, ów szczęśliwiec pracując w obu przedsięwzięciach ma możliwość zarabiania więcej. I nie trzeba stawać się kierownikiem projektu czy PMem, czy co tam jeszcze wymyślono, aby utrudnić nam dostęp do zysków.

Pytanie tylko, czy nam się chce. Czy mamy wystarczająco motywacji, aby spróbować? I najważniejsze, czy jesteśmy społeczeństwem, które ceni zaangażowanych i pracowitych (i nie zarobionych, tylko pracujących)? Na to mam jedynie negatywne odpowiedzi. A Ty?

p.s. Znacznie uprościłem rozumowanie, bo pewnie nie powstałaby ekonomia, gdyby to było takie proste, ale niektóre rzeczy zdają się być w rzeczywistości proste, a tylko my sami je niepotrzebnie komplikujemy. Jak w sytuacji nieodpowiednich narzędzi do problemu.

13 października 2010

O warsjawie i monadach w Clojure - nauka wspólnie jako sposób własnego rozwoju

7 komentarzy
Warszawska Grupa Użytkowników Technologii Java (Warszawa JUG)

Warsjawa 2010


Niedługo powinna wystartować rejestracja na bezpłatną konferencję grupy Warszawa JUG - warsjawa 2010, na której będzie możliwość wysłuchać ciekawych tematów o Javie, językach alternatywnych na JVM oraz o sztuce programowania (aka software craftsmanship). To już za niecałe 2 tygodnie, w sobotę, 23.10.2010 w Warszawie (potwierdzamy dostępność sali na MIMUW).

Odzew zainteresowanych udziałem jest, ale przede wszystkim w roli słuchacza, a już samych prezenterów jak na lekarstwo. Zachodzę w głowę skąd taki obrót spraw? Gdyby porównać naszą aktywność rok-do-roku (korzystając z podobnych zestawień wyników finansowych firm), to powiedziałbym, że spadek jest ponad 50%! Bardzo mnie martwi wyraźny trend spadkowy zainteresowania możliwością wystąpienia na konferencji, która jest wspaniałą wizytówką naszej wiedzy (nawet w fazie aktywnego rozwoju), czyli własnej reklamy, czy (odrzucając sprawy przyziemne i szukając czegoś bardziej wzniosłego) po prostu dzielenia się wiedzą ze społecznością javową. Czyżby to wakacje, a może pogoda?! A może już pozakładaliście własne restauracje, czy inne biznesy, aby czym prędzej zapomnieć o tej ciągłej informatycznej gonitwie?! Nawet na naszych blogach jakoś ciszej, a nie zauważyłem, aby rozwój narzędzi, które wykorzystujemy na codzień osłabł, a ich mnogość gwarantuje możliwość rozwoju własnego warsztatu programistycznego na wielu płaszczyznach.

Mimo swojej nazwy - warsjawa - konferencja jest dla wszystkich zainteresowanych programowaniem w Javie i w ogólności bez względu na miejsce stacjonowania. Nie jest to w żaden sposób zawężone do aktywistów warszawskich! To mówię ja, (współ)organizator :) Zainteresowani wystąpieniem na warsjawie proszeni są o kontakt ze mną na priv, albo zgłoszeniu tematu na forum Warszawa JUG w wątku - Zbieranie tematów wystąpień.

Nie przewidujemy wystawnych bankietów, jedzenia, czy innych, mniej informatycznych dodatków podczas warsjawy, ale istnieje możliwość zmiany tego stanu rzeczy - wszystko zależy od hojności naszych patronów (zwanych również sponsorami). Firmy, które są zainteresowane udziałem w roli patrona konferencji warsjawa 2010, proszone są o kontakt ze mną. Na chwilę obecną rozmawiamy z jednym, ale wierzymy, że to się niebawem zmieni.

Tyle jeśli chodzi o warsjawę 2010, na której będzie i Clojure w wykonaniu Marcina Rzewuckiego, który naukę tego języka postanowił wdrożyć w życie prowadząc własnego bloga. Warto zaglądać.

Słówko o Clojure


Jak wieść niesie, "umoczyłem" na dobre w programowaniu funkcyjnym z Clojure i moją uwagę przykuły monady. Wzięło mnie nawet na uczestniczenie w wykładach z teorii kategorii i póki co, mam wiele z tym frajdy (więcej w Monady w Clojure - wstęp do maybe-m - kontynuacja i Teoria kategorii w podstawach informatyki na MIMUWie). Pewnie monad nie będzie na tych wykładach, ale chociaż przypomnę sobie ich podwaliny - na razie wałkowana jest algebra uniwersalna (z której nota bene miałem pisać swoją pierwszą pracę magisterską o minimalnych, lokalnie skończonych rozmaitościach - się jakoś tak nie udało). Czy mi ta wiedza do czegokolwiek potrzebna, jeszcze nie wiem, ale skoro i tak wykorzystujemy jedynie 5-10% całej "mocy obliczeniowej" i pamięci naszego mózgu, więc nie obawiam się, że nie będzie miejsca na inne rzeczy. Ach, "A co z czasem?", ktoś zapyta. Cóż, mimo nowego wydania Civilization V i oczekiwania na nie przez dobre kilka miesięcy, wybrałem...programowanie funkcyjne i monady. Jak wyjdzie na MacOS, może zmienię zdanie.

Słówko o monadach


Dzisiaj udało mi się przebrnąć przez kilka artykułów dot. monad, tyle, że w wykonaniu C#, F# i Haskella (można śledzić moją aktywność na twitterze, albo delicious). Niewiele o samym Clojure - ot, pojedynczy artykuł, który już czytałem i który zamiast wyjaśnić "gdzie", wyjaśnia jedynie "jak". Podobno zrozumienie "jak" pomaga w zrozumieniu "gdzie", ale biorąc pod uwagę niewielką znajomość samego Clojure, trudno mi dostrzec ich zastosowanie. Widzę jednak światełko w tunelu. Postanowiłem rozdystrybuować poznawanie monad na większą populację, aby bardziej zaktywizować społeczność javową i wpadłem na taki pomysł.

Pomysł wspólnej nauki z monadami w tle


Pomysł opiera się na współpracy dwóch stron - strony imperatywno-obiektowo-javowej (to Ty, On i Ona, i Wasi znajomi - programiści Java, ale nie tylko, bo każdy język mile widziany) i strony monadycznej (w tej roli na razie sam ja z Clojure, ale grupa wciąż otwarta dla innych).

Zabawa polega na tworzeniu kodu javowego, który rozwiązuje zadane przeze mnie wcześniej zagadnienie programistyczne o niewielkim skomplikowaniu, aby każdy programista javowy mógł je rozwiązać, a moim zadaniem będzie przedstawienie rozwiązania monadycznego w Clojure. W ten sposób upiekę dwie pieczenie na jednym ogniu - na podstawie przykładów zaczerpniętych z naszego światka javowego poznamy monady, a ja nie będę musiał wymyślać przykładów w Javie, które ostatecznie mogłyby zostać okrzyknięte trywialnymi i stronniczymi na rzecz monad. I nie chodzi o tricki programistyczne, ale rzeczywiste rozwiązania, które używasz, albo byłyby w użyciu podczas Twoich projektów. Ja nie będę choćby sugerował rozwiązania. Wezmę takie, które zostanie okrzyknięte najbardziej racjonalnym.

Do formatowania i kolorowania kawałków kodu można korzystać m.in. z serwisu gist.github.com, ale i pastebin.com czy www.copypastecode.com. Można również zamieszczać je w komentarzach do tego wpisu.

Problem 1: Napisać metodę, która zwraca walutę, dla pracownika z danego departamentu międzynarodowej korporacji.
Pracownik jest przypisany do departamentu (np. poprzez mapę - pracownik-departament), departament do kraju, a kraj do waluty. Funkcja na wejściu dostaje nazwę, identyfikator, lub cokolwiek jednoznacznie reprezentującego pracownika, a na wyjściu symbol waluty, np. dla "Jacek" powinno być "PLN", a dla "John" "USD", a "Tomek" i "Mateusz" dawaliby "CHF".

Problem 2: Znaleźć wszystkie kombinacje liczb, które pomnożone dadzą w wyniku zadaną liczbę.
Na wejściu metoda otrzymuje liczbę, która jest iloczynem poszukiwanych par. Pary (a,b) i (b,a) są sobie równe, ale tak na prawdę nie ma to znaczenia. Dla wejścia 5 byłoby to {(1,5)}, ale dla 10 dostaniemy {(1,10), (2,5)}.

Chciałbym móc skorzystać z tej formy współpracy już podczas mojego, najbliższego wystąpienia o Clojure podczas inauguracyjnego spotkania Warszawa JUG w najbliższy wtorek, 19.10. Więcej w Otwarcie nowego sezonu - 19.10 z "Wstęp do programowania funkcyjnego z Clojure".

Może wcześniej udałoby mi się jeszcze przedstawić kilka wpisów o monadach z Twoim rozwiązaniem na blogu? Pomożecie? Na pewno!

12 października 2010

Funkcje vs stałe - funkcyjne przypisanie

0 komentarzy
Niektóre proste rzeczy przychodzą z pewnym opóźnieniem i nawet jeśli wydają się być albo wręcz są proste, trzeba czasu, aby dotarło to do odpowiednich miejsc w mojej korze mózgowej. I później są kwiatki! Sprawa rozbija się o nawyk poprawnego czytania składni Clojure, którego jeszcze nie nabyłem, ale każdy dzień sprawia, że czuję, że jestem bliżej.

Zastanawiało mnie ostatnio, dlaczego taka konstrukcja - forma w Clojure:
(defn- year-now [] (. (DateTime.) getYear))
miałaby być lepsza od tej:
(def- year-now (. (DateTime.) getYear))
Rozwiązanie przyszło, kiedy zamieniłem obie konstrukcje na odpowiedniki w Javie - pierwsze to po prostu deklaracja prywatnej funkcji (przez makro defn-), a drugie to stała, również prywatna. Kluczem jest wystąpienie owych nawiasów klamrowych, które są miejscem deklarowania "imiennych" parametrów. W pierwszym przypadku, funkcji, każdorazowe wywołanie da inną wartość, podczas gdy w drugim otrzymamy tę samą. Możnaby powiedzieć, że funkcja year-now nie jest funkcją czystą, bo różne jej wywołania mogą skutkować dwiema różnymi odpowiedziami. Nie będzie to zbyt odkrywcze, jeśli napiszę, że jest to nielada problem nie tylko dla programistów funkcyjnych, ale i imperatywno-obiektowych, gdzie bez znajomości implementacji przetestowanie działania funkcji jest nietrywialne.

Kolejnym "opóźnieniem" w moim mentalnym rozwoju było zrozumienie działania przypisania
(def a 1)
do...funkcji! Gdybym czytał o tym wczoraj, zapewne byłbym pierwszym, który zapytałby "Jak to?!" Czyż dowolna aplikacja nie jest po prostu jedną wielką funkcją?! W Javie mamy statyczną metodę main(String..), która definiuje punkt startowy i tylko w ten sposób polecenie java z podaną klasą na linii poleceń wie jak ją uruchomić. Taki jest kontrakt.

Gdyby się temu przyjrzeć, to zadeklarowanie stałej final int a = 5 w Javie, tak na prawdę nie różni się niczym od przekazania parametru wejściowego funkcji o nazwie a, np. void metoda(int a) { // użycie a jak stałej }, w której a występuje na tych samych zasadach, co zadeklarowanie jej jako stałej bezpośrednio w ciele. Proste, nieprawdaż? I tak, podczas lektury A monad tutorial for Clojure programmers (part 1) doznałem wspaniałego efektu Aha! i zrozumiałem tak oczywistą oczywistość.

W Clojure poniższe konstrukcje są sobie (prawie) równoważne.
(def a 1)

(let [a 1] a)

((fn [a] a) 1)
Czy w ogóle istnieje jakakolwiek różnica? Różnica jest i to znacząca. Przypisanie wartości do stałej jest jednorazowe, w miejscu jego wystąpienia (w Javie możemy odłożyć ten krok, aż do wykonania konstruktora), podczas gdy zbudowanie funkcji w roli przypisania (opakowanie przypisania funkcją) pozwala na dynamiczne przypisanie w dowolnym momencie wywołania jej z innymi wartościami. Możnaby założyć, że przypisanie jest "lukrem", który zamieniany jest podczas kompilacji na wykonanie właściwej funkcji z pojedynczym parametrem. Jeśli funkcja jest bytem pierwszej kategorii, to nie ma w tym nic odkrywczego.

Załóżmy, że mamy taką sekwencję wyrażeń (wszystkie równoważne):
(def a 1)
(println a)

(let [a 1]
  (println a))

(def f 
  (fn [a] a))
(f 1)
Jedynie ostatnie "przypisanie" możemy wykonywać wielokrotnie, każdorazowo podając inną wartość na wejściu. Pierwszą i drugą konstrukcję (formę w Clojure) możemy zmodyfikować w kodzie, przesłaniając poprzednie wystąpienie, ale tylko ostatnią konstrukcję funkcyjną nazwałbym w pełni samoistną i wielokrotnego użytku.

To musi mieć wpływ na nasz warsztat imperatywno-obiektowy w Javie. Zauważam jednak pewien problem - brak wsparcia dla funkcji jako bytów pierwszej kategorii w Javie, więc nie ma mowy o ich przekazywaniu do funkcji wyższego poziomu (takich, które akceptują wejście z funkcją). Tutaj właśnie widziałbym rolę Clojure jako języka wspierającego nasze programowanie w Javie - do pisania zamkniętych procedur.

Gdzieś znalazłem takie stwierdzenie, że początkowo programujemy z konstrukcjami prostymi - przekazywanie wartości do funkcji, kolejnym krokiem jest budowanie funkcji wyższego poziomu, aby w kolejnym kroku szukać...monad. Był jeszcze jeden poziom, ale nie mogę sobie go przypomnieć. Gdyby przełożyć to na język kaski, to jeszcze nie wiem, czy i w ogóle można na tej wiedzy zarobić, ale zarobić *się* można ucząc się tego wszystkiego bez praktycznego wykorzystania :)

06 października 2010

Monady w Clojure - wstęp do maybe-m - kontynuacja i Teoria kategorii w podstawach informatyki na MIMUWie

7 komentarzy
Wczoraj opisywałem moje dokonania w (przynajmniej częściowym) zrozumieniu działania monad w Clojure reprezentowanych przez monadę maybe-m. Dzisiaj wysłuchałem 2 prezentacji wokół tego tematu i przeczytałem artykuł o monadach na przykładzie ich realizacji w Pythonie i Haskellu. Nic specjalnie odkrywczego, ale coś mnie tknęło, aby jeszcze sprawdzić, czy i jak definiuje się monady na bazie mojej niewielkiej wiedzy w tym temacie.

Zacząłem od prostej modyfikacji monady maybe-m, w której wartość nieprawidłowa nil kończy przetwarzanie. Postanowiłem wprowadzić pewne urozmaicenie, które jakkolwiek nie wprowadza niczego specjalnie odkrywczego w samym działaniu monady, to może jednak uprościć ich zrozumienie.

Załóżmy taką definicję monady nothing-m, której zadaniem jest podmiana wartości nieprawidłowej.

(defmonad nothing-m
   "Monad describing computations with possible failures which are
    represented by nil. The failure is changed into :nothing.
    This monad is based upon maybe-m monad from Clojure's c.c.monads
    Author: Jacek Laskowski"
   [m-result (fn [v] v)
    m-bind   (fn [mv f]
               (if (nil? mv) (f :nothing) (f mv)))
    ])
Każda monada musi dostarczać w swojej podstawowej realizacji 2 metody - m-result oraz m-bind. Pierwsza, m-result (trafniej byłoby raczej nazywać ją m-inject) opakowuje wartość w wartość monadyczną. Druga, m-bind, to funkcja (prawie)odwrotna do m-result, bo częściowo rozpakowuje przekazaną wartość monadyczną i działa na niej funkcją. Obie realizują pewien kontrakt monadyczny, o którym jeszcze kiedyś tam napiszę (jak sam zrozumiem temat :)).

W mojej realizacji kontraktu monadycznego, każdorazowe napotkanie wartości specjalnej (obecnie tylko nil, ale możnaby wyobrazić sobie cały ich zbiór) kończy się zwróceniem :nothing.

user=> (domonad nothing-m
  [m (do (println 1) :m)
   n (do (println 2) nil)
   o (do (println 3) :o)
   p (do (println 4) nil)
   r (do (println 5) :r)]
    (println m n o p r))
1
2
3
4
5
:m :nothing :o :nothing :r
nil
Proste, co? Przy tej realizacji założeń - podmiana wartości specjalnej na podaną - przypomina mi działanie aspektów AroundInvoke, które mogą wykonać dodatkowe operacje, np. podmiana wyniku działania funkcji na zadany bez zmiany tejże. Dla niektórych zapewne bliższe to jest wzorcowi Dekorator.

A skoro o monadach, to zajrzałem na przedmioty oferowane na wydziale Matematyki, Informatyki i Mechaniki Uniwersytetu Warszawskiego (MIMUW) pod kątem tych, które poruszają tematykę programowania funkcyjnego z naciskiem na coś strawnego jak Clojure albo Erlang, ale nic co przypadłoby mi do gustu. Wpadł mi do głowy pomysł, aby sprawdzić teorię kategorii i jakież było moje zdziwienie, kiedy trafiłem na przedmiot Teoria kategorii w podstawach informatyki. Pomyślałem sobie, że może by tak odświeżyć pamięć i zamiast czytać, możnaby posłuchać, a jeszcze byłaby możliwość porozmawiać, więc napisałem do prof. Andrzeja Tarleckiego. Nie upłynął kwadrans, a ja już miałem odpowiedź!

Szanowny Panie,

Ostatecznie ustalony termin zajec to:

piatki, 14.00-15.30, sala 5870 (pierwsze zajecia w tym tygodniu, 8/10)
wtorki, 12.15-13.45, sala dopiero bedzie ustalona.

Prowizoryczna strona wykladu:
http://www.mimuw.edu.pl/~tarlecki/teaching/ct/index.html

O ile mi wiadomo, wyklady uniwersyteckie sa otwarte - wiec jesli ma Pan ochote, to zapraszam. Aha, zajecia beda prowadzone w jezyku angielskim (przynajmniej jeden student jest obcokrajowcem).

Z powazaniem,
Andrzej Tarlecki


Akurat w piątek o 14:00 mam czas, aby zajrzeć, więc dlaczego nie?!

05 października 2010

Monady w Clojure - wstęp do maybe-m

0 komentarzy
Kto śledzi moje poczynania na twitterze (kanał @jaceklaskowski) już wie, że przynajmniej monada maybe-m w Clojure jest rozpoznana (z dokładnością do metod m-return i m-bind).

Kiedy kolejny raz przesłuchiwałem nagrania z prezentacji Josha Grahama podczas konferencji QCon i jednocześnie próbowałem się z moimi "wymyślnymi" (czytaj: trywialnymi do bólu) przykładami w Eclipse z CounterClockWise (CCW), wszystko stało się jasne. Zgoda. Może nie wszystko, ale więcej i chociażby monadę maybe-m mogę zaliczyć do tych trywialniejszych.

Nie jestem w stanie wyrazić tego błogiego stanu uniesienia, kiedy w końcu wysiłek zrozumienia monad w Clojure nie idzie na marne i po przynajmniej miesiącu zagłębiania się w różnego rodzaju materiały w Sieci i poza nią, maybe-m zaczyna funkcjonować zgodnie z oczekiwaniami. Teraz powinno być mi łatwiej wyjaśnić, cóż magicznego jest w monadach, co powoduje chęć ich zrozumienia u wielu, acz niewielu niestety ma wystarczająco dużo motywacji, aby przebrnąć przez dostępny materiał i przetrawić go. Wierzę, że seria wpisów, które zaplanowałem na ten temat wypełni choć po części tę lukę (i nie przyczynię się jednocześnie do jeszcze większego zaciemnienia tematu, a wręcz przeciwnie).

Jako, że rozpiera mnie, aby zgłębić więcej o monadach (prawdopodobnie będę musiał przeczytać jeszcze raz artykuły, które odznaczyłem jako przeczytane - patrz moje konto na Delicious), teraz przedstawię jedynie zrąb informacji, aby w kolejnych odsłonach przymierzyć się do artykułu o monadach z przykładami. Gdyby ktoś zechciał mi pomóc, proszę o pobranie źródeł z repozytorium monady-artykuł na GitHubie i przesyłanie łatek. Pisanie artykułu w ten sposób, to zrealizowanie nauki git i Clojure, i monad, i pewnie kilku innych rzeczy za jednym zamachem, więc...czekam na aktywny odzew. Niech nawet będzie na poziomie sugestii, bo bez tego materiał będzie tak zrozumiały, jak osoby przedstawiające.

Tyle w ramach rozgrzewki. Pora na wyjawienie "prawdy oczywistej" o monadach w krótkim wprowadzeniu do wprowadzenia do monady maybe-m w Clojure. Przypomnę, że tym razem nie będzie kodu w Javie - on będzie wynikiem pracy kolektywu :) Za to będzie Clojure. Ostrzegałem.

Mała rozgrzewka w postaci kodu w Clojure. Co będzie jego wynikiem?

(ns
  #^{:author "Jacek Laskowski"
     :doc "Examples with monads"}
  monads
  (:use [clojure.contrib monads]))

(domonad maybe-m
  [m (do (println 1) :m)
   n (do (println 2) nil)
   o (do (println 3) :o)
   p (do (println 4) nil)
   r (do (println 5) :r)]
    (println m n o p r))
Najważniejsza w tym przykładzie jest konstrukcja (domonad maybe-m ...) (linia 7), której zadaniem jest wykonanie serii obliczeń (ang. computations) w "środowisku" monady maybe-m. Jej działanie w skrócie można przedstawić jako - jeśli w jakimkolwiek kroku obliczeń, jedno z nich zwróci nil, kolejne nie będą wykonane, jak i końcowe, podsumowujące wyrażenie - w naszym przypadku (println ...) na linii 13.

A zatem jaki będzie wynik?

Przeanalizujmy konstrukcje występujące w ciele (domonad maybe-m ...) zaczynające się nawiasem kwadratowym (symbolizującym tablice w wielu językach programowania, np. Javie) - linie 8-12. Konstrukcja tablicowa [] wymaga parzystej liczby form i lewej stronie przypisuje wartość z prawej. Tym samym staną się stałymi lokalnymi (nie zmiennymi!). I tak kolejno dla każdej pary (przecinek jest opcjonalny i spacja wystarczy jako separator elementów w tablicy). W naszym przypadku, litery od m do r zostaną zainicjowane kolejno typem kluczowym :m, później nil i tak dalej. Dodatkowo dla poprawy zrozumienia, co się dzieje w każdym kroku dodałem wykonanie (println ...), aby wykonanie inicjowania zostawiło jakikolwiek ślad na konsoli (i abym mógł poznać działanie kodu bez uruchamiania debuggera). Jako, że w jednym kroku przypisania wykonujemy dwie funkcje - (println ...) oraz zwrócenie wartości - konieczne było opakowanie ich funkcją (do ...). To kończy wyjaśnianie sekcji inicjującej.

Ostatnia linia 13. z (println m n o p r) odpowiada wypisaniu wartości stałych m, n, o, p, r na ekran. To odpowiada wywołaniu System.out.println w Javie.

A zatem jaki będzie wynik?

Potrzeba więcej? Zgoda.

Konstrukcja (domonad maybe-m ...) jest tak na prawdę makrem w Clojure, co oznacza, że podczas kompilacji zostanie zamieniona na odpowiadające jemu wywołania funkcji. Można się o tym przekonać korzystając z funkcji (clojure.walk/macroexpand-all). Wynikiem jej działania jest "rozwinięcie" makra na odpowiednie wywołania funkcji w Clojure. Nie zapomnijmy o wykluczeniu wykonania formy będącej argumentem dla (macroexpand-all) apostrofem albo funkcją (quote)!

user=> (macroexpand-all '(domonad maybe-m
  [m (do (println 1) :m)
   n (do (println 2) nil)
   o (do (println 3) :o)
   p (do (println 4) nil)
   r (do (println 5) :r)]
    (println m n o p r)))

(let* 
  [name__518__auto__ maybe-m
   m-bind (:m-bind name__518__auto__)
   m-result (:m-result name__518__auto__)
   m-zero (:m-zero name__518__auto__)
   m-plus (:m-plus name__518__auto__)]
  (do 
    (m-bind (do (println 1) :m) (fn* ([m] 
    (m-bind (do (println 2) nil) (fn* ([n]
    (m-bind (do (println 3) :o) (fn* ([o] 
    (m-bind (do (println 4) nil) (fn* ([p] 
    (m-bind (do (println 5) :r) (fn* ([r] 
    (m-result (println m n o p r)))))))))))))))))))
Pewnie te ostatnie nawiasy najbardziej intrygujące, co? ;-) Idzie się do nich przyzwyczaić (jak do klepania klamrowych w Javie).

Pozostaje zrozumieć, co robią metody m-bind oraz m-result. Pochodzą one z monady, w ramach której działamy, co w naszym przypadku będzie monadą maybe-m. Poniżej jej definicja.

(defmonad maybe-m
   "Monad describing computations with possible failures. Failure is
    represented by nil, any other value is considered valid. As soon as
    a step returns nil, the whole computation will yield nil as well."
   [m-zero   nil
    m-result (fn m-result-maybe [v] v)
    m-bind   (fn m-bind-maybe [mv f]
               (if (nil? mv) nil (f mv)))
    m-plus   (fn m-plus-maybe [& mvs]
        (first (drop-while nil? mvs)))
    ])
Funkcja m-result oczekuje na wejściu pojedynczego parametru i po prostu zwraca go. Innymi słowy, przekazuje wejście na wyjście bez zmian. Tym samym, opakowanie formy przez m-result nie zmienia wyniku formy (bo m-result nic nie zmienia). Jedynym "cudem" jest działanie m-bind, które występuje, aż 5 razy w naszym przykładzie. Odpowiada to liczbie wykonywanych obliczeń. Funkcja m-bind dostaje na wejściu parametr (wartość monadyczną) i sprawdza, czy jest nil. Jeśli tak, zwraca nil. Zwrócenie nil, efektywnie wyłącza wykonanie kolejnych obliczeń, które mogłyby być niezwykle kosztowne - czasowo i/lub finansowo (!)

A zatem jaki będzie wynik?

Teraz wszystko powinno być jaśniejsze. W wyniku działania monady maybe-m otrzymamy wynik ostatniego wyrażenia tylko wtedy, gdy każde z obliczeń (może ich być dowolna liczba) *nie* zwróci nil. W przypadku zwrócenia nil, przetwarzanie się zakończy. Stąd możemy zobaczyć na konsoli jedynie 1 i 2 z przypisania m i n, które "dotknie" nil, co zakończy wykonywanie kolejnych instrukcji.

user=> (domonad maybe-m
  [m (do (println 1) :m)
   n (do (println 2) nil)
   o (do (println 3) :o)
   p (do (println 4) nil)
   r (do (println 5) :r)]
    (println m n o p r))
1
2
nil
Czy teraz jest już łatwiej zrozumieć, dlaczego warto stosować monady i dlaczego nazywa się je kontenerami, podobnie jak kontener servletów, czy EJB znanych z serwerów JEE? Monady, podobnie jak kontenery JEE, udostępniają środowisko dla naszych bytów - konstrukcji obliczeniowych. Obliczenia w monadach mogą być tak proste jak w naszym przykładzie, w którym sprowadziłem do przypisania z poprzedzającym je wypisaniem na ekran, ale równie dobrze mogą być tak skomplikowane jak pobranie danych z bazy danych, albo ekranu prezentowanego użytkownikowi i tylko w przypadku zwrócenia wartości innej niż nil (albo wybranej przez nas, kiedy stworzymy własną monadę), pozwala się im na kontynuowanie wykonania kolejnych obliczeń - na ich uruchomienie.

Do zapamiętania: zamiast serii if'ów, wystarczy jedynie opakować serię obliczeń w monadę maybe-m i oczekiwać zatrzymania przetwarzania, w momencie pojawienia się niedozwolonej wartości - w naszym przypadku nil. Co było do okazania :-)