06 października 2010

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

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?!

7 komentarzy:

  1. Aj, daleko trochę do Wawy. Chciałbym o czymś takim posłuchać na swojej uczelni, ale mogę chyba tylko pomarzyć...

    OdpowiedzUsuń
  2. Czesc Jacek,

    Zauwazylem Twoj adres e-mail na liscie adresatow i postanowilem sprawdzic czy chodzi o tego samego Jacka Laskowskiego i okazuje sie, ze tak :)

    Mam nadzieje, ze mnie jeszcze pamietasz. Byc moze spotkamy sie na tych zajeciach bo ja wlasnie tez planuje na nie chodzic. :)

    OdpowiedzUsuń
  3. No wiesz, jak mógłbym zapomnieć - tego co w Cocoonie rozdaje karty? I bodaj niedawno jeszcze pomagał mi zrozumieć monady? Wybacz, ale udam, że nie słyszałem tej uwagi z "jeszcze pamiętasz" :) Teraz możesz już tylko liczyć na co najwyżej wzmiankę na blogu, kiedy pojawi się relacja z wykładu. Zapowiada się ciekawie.

    OdpowiedzUsuń
  4. Hej :)

    Troche sie pozmienialo jesli chodzi o Cocoona. W skrocie mowiac odszedlem od Javy na rzecz Scali i ogolniej zajalem sie bardziej teoretyczna czescia informatyki.

    Wczoraj wrocilem do Polski z praktyk w Google, ktore troszeczke mnie znowu zblizyly do Javy, ale tylko troszeczke i tylko na chwile:
    http://scalagwt.gogoego.com/

    (pracowalem nad tym projektem jako intern)

    A ciebie Jacek co sklonilo by zblizyc sie do jasnej strony programowania (tzn programowania opartego o jakies teoretyczne fundamenty)? :)

    OdpowiedzUsuń
  5. Mnie zwykła ciekawość, co oferuje inny sposób programowania - funkcyjny. Zacząłem badać, czytać i tak mnie wciągnęło. Przez 15 lat bawiłem się Javą i jakkolwiek nic bardziej nie sprawiało mi satysfakcji (nie licząc rzeczy nietechnicznych), to zaraziłem się ogólną fascynacją językami funkcyjnymi, w których wiele można znaleźć dla warsztatu programisty javowego. Postaram się to pokazać na kolejnym spotkaniu WJUGa i wtedy zobaczymy, czy i jak bardzo może to być interesujące/uzależniające dla innych.

    OdpowiedzUsuń
  6. Hmmm, pogrzebałem w Twoich ostatnich wpisach i widzę, że Cię bardzo programowanie funkcyjne wciągnęło. Clojure jest faktycznie pierwszą sensowną implementacją LISP-a w Javie, tylko pytanie na ile to-to jest dojrzałe do użycia gdziekolwiek.

    Pierwsze i podstawowe pytanie to binarna kompatybilność wsteczna. To jest gigantyczny problem różnych nowinek, między innymi Scali. Instaluje nową wersję Scali i okazuje się, że wszystko, co mam skompilowane nie działa. Trochę nędza. Nie mam pretensji o brak kompatybilności na poziomie kodu źródłowego, ale binarna powinna być.

    Druga rzecz, to odwieczne pytanie, dlaczego LISP się nie przyjął przez 30 lat skoro jest taki świetny. Odpowiedź jest przewrotna, a tak na prawdę to są dwie odpowiedzi.

    Odpowiedź 1. LISP ma paskudną składnię, która jest niewygodna przy dłuższych kawałkach kodu i nie ma znaczenia to, że wynika to po części z przyzwyczajeń. Dodatkowo LISP w pewnym stopniu narzuca programowanie funkcjonalne. W pewnych sytuacjach jest ono bardzo wygodne, np. parsowanie struktur drzewiastych - z tego powodu XSLT jest językiem funkcyjnym, w a Scali się tak fajnie pracuje z XML-em. Ale jest także bardzo dużo zagadnień, w których paradygmat funkcjonalny jest zwyczajnie niewygodny. Z tego powodu optymalna jest hybryda, coś jak Scala, tylko może nie tak "po uniwersytecku" barokowo rozbudowana.

    Odpowiedź 2. LISP nie jest popularny? Wolne żarty, jest to najpopularniejszy język obecnie używany. Brzmi niewiarygodnie? Ale to prawda. Jest taki dialekt LISP-a, który jest mega popularny, a nazywa się JavaScript: http://www.crockford.com/javascript/javascript.html!

    Piotr K, xoft.pl

    OdpowiedzUsuń
  7. Cześć Piotr, odnośnie "tylko pytanie na ile to-to jest dojrzałe do użycia gdziekolwiek" to właśnie to pytanie jest powodem dla moich poczynań funkcyjnych z Clojure. Jedno jest pewne, bez względu na odpowiedź, mój warsztat programistyczny nie będzie tym samym, jaki był przed przedsięwzięciem. Wierzę, że w naszej branży każda zmiana jest dobra. To mi wystarczy, aby kontynuować naukę.

    OdpowiedzUsuń