08 kwietnia 2013

Radość programowania == progfun - programowanie funkcyjne w Scali i Clojure

Tak mnie jakoś dzisiaj naszło. Pewnie to pogoda, bo słońce praży na zewnątrz, że aż trudno znaleźć zajęcie, które mogłoby przytrzymać człowieka na dłużej przy komputerze. Śmiem twierdzić, że człowiek to taka bestia, która zwykle dąży do poszukiwania zajęć, które łączą w sobie cechy bycia użytecznymi, a przy tym jeszcze niosą ze sobą ładunek pozytywnego myślenia i energii. Takie motywatory.

Po przydługiej zimie potrzeba rozruszać członki!

Nauka nowego języka programowania może być użyteczna i ucząca (pozytywnego) myślenia. Może jednak stracić swój blask, kiedy wokoło tyle równie ciekawych rzeczy. I jeszcze to słońce!

Podczas szkolenia na coursera.org - Functional Programming Principles in Scala - które polecam każdemu, zwróciłem uwagę na jego skrót - progfun. I wtedy przypomniałem sobie o owej radości programowania, o której tyle się czyta. Skoro już tworzymy oprogramowanie, to niech to będzie maksymalnie energetyczne zajęcie. I niech dostarcza radości!

Jeśli pracujesz z Javą, a brakuje Ci trochę fun w pracy, pochyl się nad programowaniem funkcyjnym, które chociażby z nazwy pozwala sądzić, że będzie zabawne, zajmujące, a nawet może i pożyteczne (może i w karierze!).

Kiedykolwiek pojawi się wątpliwość, czy nauka Scali czy Clojure to dobra inwestycja w przyszłość, pomyśl o polskim skrótowcu dla PROGramowania FUNkcyjnego - progfun. Kiedy zaaplikuje się angielskie znaczenie do tego, zrobi się od razu przyjemniej. Pojawi się FUN!

Niektórzy mogliby również przetłumaczyć "functional" na funkcjonalne (!)

Czy trzeba więcej powodu poznania języka funkcyjnego niż ów "FUN" oraz użyteczność tworzenia aplikacji funkcjonalnych?! Pozwól sobie na chwilę z Clojure lub Scala, a z pewnością nie będziesz żałował(a).

I ciekawostka z pola poznawania Scali - różnica między def a val jest znacząca. Pierwszy - def - opóźnia wyliczenie wartości aż do miejsca faktycznego użycia (wywołania). Drugi - val - wymusza wyliczenie wartości w miejscu definicji, aby już od tego momentu nazwa wskazywała na wartość wyrażenia.

Może to i niuans, ale to właśnie takie sztuczki i kruczki pozwalają mi na znalezienie owego FUNu w programowaniu i nakręcają na poszukiwanie kolejnych.

Z tą wiedzą powinno być już łatwo określić czas działania poniższego kawałka kodu w Scali.
scala> import java.util.concurrent.TimeUnit.SECONDS
import java.util.concurrent.TimeUnit.SECONDS

scala> def trwa5sekundDef = { SECONDS.sleep(5); 5 }
trwa5sekundDef: Int

scala> trwa5sekundDef
res2: Int = 5

scala> val trwa5sekundVal = { SECONDS.sleep(5); 5 }
trwa5sekundVal: Int = 5

13 komentarzy:

  1. Po Twojej pochwale tego kursu na WJUG'u zabrałem się za niego i jestem na dobrej drodze, by go ukończyć. Dzięki za motywację ;)

    OdpowiedzUsuń
    Odpowiedzi
    1. Super, że o tym piszesz! Podtrzymuje to moją nadzieję, że warto coś polecać (mimo oczywistej oczywistości, że różni ludzie reagują inaczej na te same zjawiska).

      Rozumiem, że Getting Started i HOFs masz na 100%? Mnie trochę "zdławiło" wymyślenie algorytmu na Coin change (brakowało mi jednego składnika sumy) i musiałem się posiłkować algorithmist.com.

      Ciekawym, co Cię zaskoczyło najbardziej podczas dotychczasowych wykładów? Co związane z ćwiczeniami? Doczytujesz coś jeszcze czy "idziesz" samymi nagraniami? Jak planujesz sobie odsłuchiwanie - wszystkie za jednym razem czy partiami? Od razu podchodzisz do ćwiczeń, czy może pod koniec dnia albo tygodnia? Zdradź własne sposoby na przyswojenie materiału. Chętnie zaczerpnę co nieco.

      Usuń
    2. Krótko o mnie: jestem studentem 3 roku, który nie ma jeszcze doświadczenia komercyjnego w programowaniu. Moim ulubionym językiem jest Java, a ten kurs to moje pierwsze zetknięcie z programowaniem funkcyjnym, więc jestem zupełnie 'zielony' ;)

      Jak na razie udaje mi się uzyskiwać 100%, ale również miałem problem z algorytmem 'Coin change' oraz z jednolinijkową implementacją funkcji 'exsists' przy wykorzystaniu 'forall' (na początku poradziłem sobie bez 'forall'). Dużo problemów miałem jeszcze z 'balance parentheses', które zajęło mi sporo miejsca - chyba mało funkcyjnie do tego podszedłem.
      Kiedy mam problemy odwiedzam forum, mnóstwo dobrych wskazówek, ale też niektóre są być może zbyt szczegółowe.

      Kurs robię korzystając z samych nagrań z odpalonym obok Eclipsem, w którym na bieżąco sprawdzam czy Martin nie oszukuje. ;) Staram się w tygodniu oglądać wykłady, a w weekend zrobić ćwiczenie. Materiał do obejrzenia nie jest długi, więc można oglądać po trochu żeby dobrze zrozumieć temat, bez strachu że się człowiek nie wyrobi.

      Assignment z Set'em dał mi dużo do myślenia, szczególnie koncepcyjnie. Progfun ogólnie mnie zadziwia, a szczególnie zupełnie inne podejście do rozwiązywania problemów oraz możliwość pisania 'one-linerów', które o dziwo działają ;)

      Usuń
    3. U mnie też forum stanowi podporę, ale pamiętam, kiedy moja wersja Coin change nie działała, a gośc na forum napisał, że to trzylinijkowiec. Wiedziałem wtedy, że dwie pierwsze to warunki końcowe, a ostatnia linia to zapewne rekurencyjne obliczenie wyniku, jednak to jedynie bardziej mnie zestresowało, bo zacząłem poszukiwać od razu rozwiązania doskonałego niż działającego. Spędziłem nad tym bodaj 3 dni, aż się poddałem i zajrzałem na algorithmist. Olśniło mnie.

      Nie robiłem jeszcze tych ostatnich zadań, ale pamiętam z poprzedniej edycji, że Set był realizowany funkcyjnie i mimo, że już miałem doświadczenie w programowaniu funkcyjnym w Clojure, to i tak realizacja w Scali była zaskakująca. Unaoczniło mi, że co problem to nowe ćwiczenie umysłowe (mimo podobieństwa do poprzednich).

      Jak widziałem na forum WJUGa, jesteś (czasami?) w Warszawie. Może należałoby się zebrać i przedyskutować techniki rozwiązywania zadań na courserze? Napisz na priv, abyśmy obgadali szczegóły. Koniecznie!

      Usuń
    4. Mi osobiście bardzo ciężko było wpaść na rozwiazanie zagadki z Set'em, podczas zeszłorocznej realizacji kursu. Wymagało to wyjścia po za nabyte ramy i ograniczenia myślowe. Jest to rzecz, którą najbardziej zapamiętałem z całego kursu.

      Usuń
    5. Mam to już za sobą! Nie powiem, żeby było łatwo, ale z pewnym doświadczeniem nabytym przez lata z Clojure, nie było niemożliwe do złamania - szczególnie z wyrażeniem exists za pomocą forall zmęczyło mnie trochę (cały dzień łaziłem i dumałem). Właśnie dla tego ćwiczenia poleciłbym to szkolenie.

      Jeśli wciąż pragniesz zgłębiać tajniki programowania funkcyjnego ze Scalą gorąco polecam Functional Programming in Scala. Książka wymiata, a ćwiczenia są wymagające. Bez ich wykonania książka jest bezwartościowa. Z nimi nabiera rumieńców.

      Usuń
    6. Zmiana sposobu myślenia to była dla mnie największa korzyść w trakcie robienia tego kursu w zeszłym roku. Też głównie zapamiętałem definicję set-ów jak funkcji sprawdzających istnienie danego elementu. Największą wartością jest właśnie nie przedstawienie nowego języka, a próba pokazania, że można myśleć inaczej na temat znanych nam problemów.

      Usuń
  2. Różnicę między def a val zdefiniowałbym nieco inaczej: def foo wylicza foo za każdym razem, gdy jest wywoływane. val foo wylicza foo tylko raz, w momencie tworzenia klasy/obiektu. Nie do końca trafne porównanie z Javą to def - metoda, val - pole. I przy okazji jest jeszcze lazy val - leniwie wyliczane val przy pierwszym użyciu, tylko raz i bezpieczne w środowisku wielowątkowym.

    Z kolei def w Clojure zastąpilibyśmy przez def/defn a val w Clojure np. przez let.

    OdpowiedzUsuń
    Odpowiedzi
    1. Dobrze to ująłeś! Zastanawiam się jeszcze nad lazy val vs def. Jak rozumiem lazy val jest wyliczane i podstawiane pod val, a def wyliczane każdorazowo (nie bardzo jeszcze umieszczam to w kontekście tworzenia instancji klasy/obiektu).

      Usuń
    2. Masz rację. lazy val to takie val, ale wyliczane przy pierwszym użyciu. Ponieważ wiąże się z synchronizacją między wątkami (coby nie liczyć wielokrotnie przez wiele wątków), lazy val niesie za sobą pewien koszt. Poznasz lazy val bardzo dokładnie pod koniec wykładów.

      def to zwykła funkcja która wylicza się przy każdym wywołaniu, w każdym wątku. Dla treningu - program do wklejenia w REPL:

      val eager = {println("val"); 42}
      lazy val lazyy = {println("lazy val"); 42}
      def fun = {println("def"); 42}

      Zauważ, kiedy i ile razy wyświetlane są poszczególne napisy.

      Usuń
    3. Właśnie mi uzmysłowiłeś, że bardziej przekonującym przykładem byłby z println, a nie TimeUnit (którego nota bene nauczyłem się od Ciebie przy okazji asynchroniczności - już nie pamiętam dokładnie).

      Podobny przykład już widziałem w książce Functional Programming in Scala. Jest wspaniała i polecam ją każdemu adeptowi programowania funkcyjnego, ale z perspektywy Scali. Naprawdę doskonała jako podręcznik do samodzielnego szlifowania warsztatu funkcyjnego. Niektórzy nawet zarzucają jej nazbyt warsztatowe podejście. Czytałeś ją może? Masz swoje funkcyjne typy (bez względu na język, a uczące/opisujące PF)?

      Usuń
    4. Cóż, zarówno sleep jak i println mają efekty uboczne, ale pauzę trochę trudniej pokazać na blogu ;-). Obecnie czytam Scala in Depth (polecam, chyba pierwsza książka o dobrych praktykach i zaawansowanych technikach) a Scali jako takiej uczyłem się z książki Oderskiego et al.

      Nie przypominam sobie żadnej przełomowej książki o PF, którą bym czytał (może na studiach). Polecałbym raczej czytanie kodu i samodzielne próby, np. http://aperiodic.net/phil/scala/s-99/.

      Usuń
    5. Scala in Depth czeka na swoje pięć minut na półce obok wielu innych ciekawych książek. Na razie siedzę w Algorithms, 4th Edition. Postanowiłem podejść do niej bardziej systemowo - czytam sekcję dziennie, aby nie stracić tempa (a z drugiej strony, aby się specjalnie nie natrudzić).

      Przełomowymi były książki o Clojure (bodajże wszystkie zaliczyłem z kilkoma jeszcze bez recenzji) oraz F# (głównie Real-World Functional Programming, With examples in F# and C# - czeka na moją recenzję), które unaoczniły mi zalety programowania funkcyjnego. Nie mogę doczekać się, aby przeczytać Structure and Interpretation of Computer Programs, Land of Lisp: Learn to Program in Lisp, One Game at a Time! oraz Let Over Lambda.

      Rozkochałem się w Functional Programming in Scala.

      Usuń