wtorek, 11 grudnia 2012

Mity edukacji

Czy lepiej jest pójść na studia czy raczej samemu próbować coś zdziałać? Tego typu pytania ostatnio coraz częściej pojawiają się na technicznych listach dyskusyjnych. Niestety rzadko kiedy ktoś daje jasną, zdecydowaną odpowiedź. Pomyślałem zatem, że może mnie się uda. Zanim jednak udzielę własnej opinii to przytoczę parę powtarzających się argumentów z obu stron:

Przeciwko studiowaniu:
  • na studiach uczysz się wszystkiego... niepotrzebnego,
  • sam uczysz się o wiele szybciej,
  • papiery i tak nie wiele dzisiaj znaczą,
  • studia kształcą tylko bezrobotnych.

Za studiowaniem:
  • 70% ludzi uczy się szybciej samemu ale prawie nikt nie wie czego powinien się uczyć,
  • studia nie są by przygotowywać ludzi do pracy ale by rozwijać "głód wiedzy",
  • duże firmy (korporacje) bez tytułu magistra a czasami nawet doktora nikogo nie zatrudniają.

Tak naprawdę to te argumenty są niewiele warte ale postaram się odnieść do każdego z nich. Zatem na pierwszy ogień idzie teza, że studia uczą samych nie potrzebnych rzeczy.

Studia jak każda inna firma czy też instytucja aby przetrwać musi realizować czyjeś potrzeby. A czyje potrzeby realizuje firma? No tych osób, które płacą. A kto zatem płaci? Nasuwa się od razu, że studenci co oczywiście jest bzdurą. Nawet w przypadku studiów prywatnych. Czesne na renomowanych amerykańskich uczelniach prywatnych pokrywają zaledwie 30% kosztów. W Polsce jest to jeszcze mniejszy procent. Amerykańskie uczelnie utrzymują się z dotacji prywatnych i państwowych, polskie natomiast praktycznie tylko z tych drugich. Czyje potrzeby realizują uczelnie? Rządu, ministerstwa czy też swoje własne "widzimisię" jeżeli dany rząd akurat daje im sporo swobody. Skoro studia nie realizują potrzeb studentów to chyba nie będzie przesadą stwierdzenie, że nie uczą one też w większości potrzebnych im rzeczy.

No dobrze ale skąd studenci mają wiedzieć czego właściwie potrzebują? Czy nie musimy im właśnie tego pokazać? Czy profesorowie tego nie wiedzą lepiej od nas samych? Z takiego myślenia wynika właśnie, że tak wiele osób pozostaje po studiach bez pracy. Dowiedzieć się naprawdę nie jest trudno. Po pierwsze musimy wiedzieć albo co chcemy robić albo ile chcemy zarabiać. Jak wiemy co chcemy robić to szukamy firmy lub też osoby, która to robi i dowiadujemy się co ona potrafi. Jeżeli wiemy ile chcemy zarabiać to szukamy zawodu, w którym osoby tyle zarabiają i tak samo dowiadujemy się od nich czego nam potrzeba. W dobie Internetu z takimi osobami możemy porozmawiać zupełnie za darmo i pewnie nam jeszcze pomogą się tego wszystkiego nauczyć. Wystarczy chcieć. Można też przejść się na rozmowę kwalifikacyjną ale nie po to by dostać pracę lecz po to tylko by zobaczyć test kompetencji i zorientować czego jeszcze nie potrafimy.

A może profesor też może nam takiej informacji udzielić? Warto kierować się w życiu zasadą, że zawsze uczymy się od ludzi, którzy osiągnęli już to co i my chcemy osiągnąć. Profesor może nam pomóc tylko w wypadku, gdy sami chcemy być profesorami :)

Głód wiedzy jest arcyciekawym argumentem. Najpierw trzeba by zdefiniować co to właściwie jest. Jak odczuwamy głód to oznacza mniej więcej tyle, że nie potrafimy myśleć o niczym innym jak tylko o tym jak zdobyć jedzenie. Zgodnie z tą przesłanką nie wydaje mi się żeby osoba głodna wiedzy czekała aż do studiów aby ktoś jej tą wiedzę podarował. Wydaje mi się raczej oczywiste, że taka osoba szuka wiedzy na wszystkie możliwe sposoby i nie zawraca sobie głowy tak długim procesem nauki jakim są właśnie studia. To raczej osoby, którym się nie chce idą do szkoły aby ktoś im wszystko pokazał żeby nie musieli sami szukać i się dowiadywać.

A co z papierami? Tu mogę pisać tylko z doświadczenia, a pracowałem u kilku pracodawców i znajomi pracowali, i znajomi znajomych, ba nawet sam byłem pracodawcą. Papier nie otwiera żadnych drzwi. Jedyne firmy, których to w ogóle obchodzi to firmy państwowe i korporacje. Tam faktycznie bez papierka nie wejdziemy. Jeżeli praca w korporacji jest naszym marzeniem to nie mamy niestety wyjścia (co do firm państwowych to mi by było wstyd pracować dla złodzieja). Oczywiście jak przejrzymy oferty pracy to prawie na każdym będzie widniało wymaganie aby być co najmniej studentem 5 roku. Jest to raczej efekt populizmu i nie należy się tym przejmować tylko wysyłać CV, a na pewno odpowiedzą i zaproszą na rozmowę.

To po co w ogóle istnieją uczelnie? Czy faktycznie tylko produkują bezrobotnych? Jak już pisałem wcześniej studia nie są ukierunkowane na studentów. Prawdę mówiąc to nigdy nie były. Studia to taki ośrodek badawczy dla profesorów, aby mogli prowadzić swoje badania czy to na potrzeby firmy czy też rządu. Im tylko na tym zależy, tylko na tym aby uzyskiwać granty i dotacje by móc prowadzić swoje badania. Nazwałbym je pieszczotliwie "ośrodkiem samorealizacji uczonych". I wcale nie chodzi o to aby ten profil zmieniać, a raczej chodzi o to aby to sobie uświadomić. Tylko my sami jesteśmy odpowiedzialni za to czego się nauczymy i czy będziemy mieli pracę. Ważne zatem jest by wiedzieć czym są uczelnie, a czym nie. A nie są na pewno miejscem, które zapewni nam pracę poza murem uczelni.

Wniosek z tego taki, że studiować się nie opłaca ale to nie oznacza wcale, że uczyć się nie opłaca. To właśnie zamiast studiować powinniśmy się uczyć i to o wiele więcej niż na studiach.

poniedziałek, 5 listopada 2012

Haskell Strings

Niedawno natrafiłem na stronę http://honza.ca/2012/10/haskell-strings, gdzie autor próbował napisać w Haskellu program realizujący takie oto proste zadanie:
  • Wczytaj plik o nazwie file, który zawiera jakieś zdania,
  • Zamień pierwszą literę każdego wyrazu na wielką,
  • Wypisz wynik na standardowe wyjście.

Ja utworzyłem sobie plik ważący 382 MB składający się z linii 'are you sure about this?'. Nie będę się długo nad tym rozwodził, wypiszę tylko najlepsze rozwiązanie jakie udało mu się znaleźć:



Czas: 0m46.615s

Autor przytacza rozwiązania w innych językach i niemal każde jest szybsze od tego w Haskellu. Weźmy na przykład jego rozwiązanie w C:



Czas: 0m4.027s

Postanowiłem spróbować pobić rozwiązanie autora w Haskellu. W rezultacie udało mi się stworzyć coś takiego:



Czas: 0m2.905s

Jak widać moje rozwiązanie okazało się szybsze od tego w C! Oczywiście rozwiązanie w C pewnie też można jeszcze poprawić ale to i tak nieźle. W każdym razie nie spodziewałem się takiego wyniku. Jeżeli do tej pory ktoś nie wierzył w szybkość programów napisanych w Haskellu to teraz chyba nie powinien mieć wątpliwości. Gorąco zachęcam do nauki!

środa, 27 czerwca 2012

Szydełkowo

Od dłuższego czasu niestety nic nie pisałem ale to wszystko z przyczyny, o której przeczytasz za moment. Otóż od ponad 2 miesięcy pracowałem nad własnym projektem sklepu internetowego w Haskellu. I... udało się! Oto jest szydełkowo! To moje pierwsze komercyjne i tak zawaansowane dzieło w Haskellu. Ale nie tylko ono jest pierwsze w moim życiu, również jest to moja pierwsza firma i moje pierwsze produkty. Znajdziesz tam sporo ręcznie wykonywanych rzeczy - rzeczy naprawdę robionych z pasji. Tak jak cały sklep w Haskellu. A przecież mogłem wykorzystać gotowe i darmowe rozwiązania. Tak, mogłem zrobić prościej ale pasja zwyciężyła. Niektórzy powiedzą, że wynajduję drugi raz koło, ale to nie prawda. Czy nie lepiej mieć 2 koła do wyboru i wybrać to lepsze? Ja właśnie chciałem być przede wszystkim lepszy, stworzyć coś co spodoba się ludziom dużo bardziej niż wszystko inne. Czy mi się udało? Sprawdź sam. Ja głęboko wierzę, że tak. A teraz parę słów o technikaliach:
  • wykorzystałem serwer http o nazwie Snap
  • wysyłanie e-maili odbywa się za pomocą HaskellNet
  • captcha generowana jest dzięki bibliotece hs-captcha
  • wykorzystałem nierelacyjną bazę danych
Jeżeli chodzi o możliwości sklepu to póki co zrobiłem to co uznałem za minimum, czyli:
  • dodawanie/edycja/usuwanie produktów
  • automatyczne tworzenie miniaturek
  • dodawanie/edycja/usuwanie newsów
  • obsługa zamówień
  • obsługa koszyka
  • generowanie wydruków z pomocą latexa
  • obsługa produktów indywidualnych - klient sam tworzy produkt na zasadzie prywatnej rozmowy poprzez sklep z jego obsługą i akceptacji wyceny. Taki produkt ląduje na jego osobistej liście produktów i w każdej chwili może go dodać sobie do koszyka.
Sklep i firmę mam zamiar dalej rozwijać i na pewno jeszcze nie jedno usłyszycie. Tymczasem zapraszam do zakupów!

wtorek, 3 kwietnia 2012

Pasja i wolność

Człowiek został stworzony aby być wolnym. Taka jest nasza natura i jest ona wyjątkowa. Dlaczego tak twierdzę? Dlatego, że nasze działanie nie jest deterministyczne pod żadnym względem. A przynajmniej nie dotyczy to wszystkich ludzi. Dla przykładu rzućmy monetą. Czy ta moneta ma wybór, na którą stronę upadnie? Oczywiście, że nie. Ona jest zmuszona upaść tak jak będą tego chciały wszystkie siły na nią działające. Podobnie się ma to w teorii ewolucji. Żadne stworzenie nie miało wyboru, po prostu musiało powstać. Powód jest prosty, każda zmiana ewolucyjna następuje pod wpływem jakiegoś czynnika. Na przykład gdy zmniejszy się ilość pokarmu, którym żywi się dane stworzenie ale za to pojawi się jego nowy rodzaj to ono nauczy się w końcu go trawić. W przeciwnym wypadku by wymarło. Nie ma tu żadnego wyboru. Nie ma więc wolności.

Co zatem sprawia, że człowiek jest wolny? Coś co nazywamy wolną wolą. Choćby była obfitość pokarmu potrafimy nic nie zjeść i umrzeć z głodu. Choćbym nikomu nie uczynił niczego złego zawsze znajdzie się ktoś, kto z chęcią by mi dokopał. I wreszcie choćby niczego mi w życiu nie brakowało zawsze będę chciał więcej.

To naprawdę jest wyjątkowe. Być może zabrzmiało to ironicznie ale nie to było moim zamiarem. Wolność jest naprawdę wspaniała i tylko ona sprawia, że możemy coś tworzyć. Gdyby nie ona żylibyśmy dzisiaj jak każde zwierzę (a może bardziej jak roślina) - oddziaływając jedynie na otoczenie. Jednak do tworzenia potrzebna jest nam jeszcze jedna ważna cecha - cecha, która jest ukryta w każdym z nas. Coś co sprawia, że o wiele więcej przyjemności odczuwamy dając coś innym niż biorąc. To coś czyni nas większymi w oczach ludzi, którym pomogliśmy. To coś daje nam szczęście szczególnie wtedy, gdy daliśmy komuś coś bardzo mu potrzebnego. To coś właśnie to popycha nas do tworzenia.

Niestety czasami górę nad nami bierze chęć bycia obdarowanym, która to jest oczywiście również przyjemna. Wówczas tworzymy co raz mniej i kombinujemy jakby tu nie robić nic, a dostawać wiele. To dotyka każdego z nas. Ba, większość z nas zapomina całkowicie o dawaniu i tylko narzeka jak to mało zarabia bo ledwie może rodzinę wyżywić. Albo, że tak ciężko pracuje, a nic z tego nie ma. Wiem co teraz myślicie. Że nie mam rodziny to nie wiem jak to jest? Akurat mam rodzinę, którą utrzymuję. Że nie pracuję ciężko? A pracuję i to czasami nawet po 14 godzin 6 dni w tygodniu. Życie dla nikogo nie jest proste. Ale może być satysfakcjonujące i to bardzo.

Czy zadałeś sobie kiedykolwiek pytanie po co właściwie pracujesz? Większość ludzi pracuje po to aby zaspokoić własne potrzeby i to niezależnie czy ma rodzinę czy nie. Jak ma rodzinę to w pierwszej kolejności chce ich potrzeby zaspokoić, a w drugiej swoje. A co kieruje przeciętnym przedsiębiorcą? Chęć zaspokojenia cudzych potrzeb. Nie jego własnych lecz cudzych. Jego własne potrzeby są na drugim planie. On doskonale o tym wie, że jak stworzy coś potrzebnego dla innych to ludzie mu się odwdzięczą i to o wiele bardziej niż ilość pracy, którą w to włożył. To jest właśnie kwintesencją wolnego rynku i ludzkiej natury. Aby mieć najpierw musisz coś dać.

Oczywiście nie dotyczy to wszystkich, wielu ludzi rezygnuje z etatu na rzecz własnej działalności tylko po to aby dostać duże pieniądze za darmo. Mam tu na myśli wszelkiego rodzaju dotacje. Co jeszcze ciekawsze nikt nie zastanowił się skąd te pieniądze pochodzą. Nikt nie pomyślał, że są one zabierane ludziom pod przymusem i to tym ludziom, którzy tak bardzo narzekają na to jak nie wiele posiadają. Wielu przedsiębiorców również po drodze zapomina o celu jakim jest tworzenie czegoś dla innych i z powrotem zaczyna kombinować jak tu nic nie robić a mieć. Jak zatem tego uniknąć? Odpowiedzią na to jest pasja. Pasja tworzenia czegoś. Każdy z nas ją ma. Pasja sprawia, że już samo tworzenie dostarcza nam szczęścia. Pasja nas wciąga, pochłania. Dzięki niej zapominamy o trudnościach i jednocześnie nie daje nam zapomnieć o celu.

Zastanów się. Jakie chcesz mieć życie? Jakie życie chcesz pokazać swoim dzieciom? Chcesz aby narzekały przez całe życie na to jak mało posiadają? Jak to państwo o nich nie dba? Jakie to emerytury są niskie? Renta za mała? A może zasiłek za mały?

Zacznij żyć. Odkryj swoją pasję. Obserwuj ile szczęścia dajesz innym a sam będziesz szczęśliwy. I wreszcie kochaj ludzi bo dla nich żyjesz.

Vim i Makefile

Ostatnio się bardzo opuszczam w publikowaniu postów ale postaram się to naprawić. Dzisiaj będzie o kompilowaniu w Vimie. Pewnie jesteście przyzwyczajeni do środowisk IDE, w których aby skompilować program wystarczy po prostu kliknąć kompiluj. Mało tego, gdy w kodzie są jakieś błędy wyświetli nam się ich lista z możliwością przejścia od razu do danej linii. Oczywiście dzisiejsze IDE oferują nam nawet sprawdzanie poprawności kodu w trakcie pisania ale nie będę się akurat tą opcją dzisiaj zajmował (choć da się również to zrobić w Vimie).

Identyczną funkcjonalność w naszym edytorze otrzymamy za pomocą komendy make. Chodzi mi tutaj o polecenie w Vimie, a nie o program o tej samej nazwie. Polecenie to uruchamia program ustawiony pod zmienną makeprg i parsuje komunikaty, które ten program wyrzuca na ekran. Domyślnie pod makeprg ustawiony jest program make ale możemy to zmienić w bardzo prosty sposób:

:set makeprg=g++

Zamiast g++ możemy wpisać dowolną nazwę programu.

No dobrze, czyli polecenie make uruchamia zewnętrzny program, parsuje jego komunikaty ale skąd ma wiedzieć co one oznaczają? Otóż porównuje je z wzorcem zapisanym w zmiennej errorformat. Wzorce zapisane są w odpowiednim formacie, o którym można dokładnie poczytać w :help errorformat. Ja ograniczę się tylko do pokazania przykładu, który z resztą był mi bardzo pomocny.

Domyślnie w tej zmiennej zapisane są wzorce komunikatów programu make ale jedynie tych angielskich. Jako, że ja mam ustawiony język polski w systemie to make również komunikuję się ze mną po polsku. I w tym momencie na domyślnych ustawieniach Vim sobie nie radzi. Dopisałem więc do errorformat dodatkowe reguły:

%Dmake[%*\\d]:\ Wejście\ do\ katalogu\ `%f',%Xmake[%*\\d]:\ Opuszczenie\ katalogu\ `%f',%D%*\\a:\ Wejście\ do\ katalogu\ `%f',%X%*\\a:\ Opuszczenie\ katalogu\ `%f'

Po krótce omówię symbole, których tu użyłem:
  • Pierwsza linia (tzn. do przecinka) mówi o tym, że make zmienia katalog, w którym kompiluje pliki. Jest to bardzo ważne, ponieważ Vim sobie zapamiętuje, w których katalogach są one kompilowane. Przydaje się to w momencie, w którym jesteśmy aktualnie w katalogu A i błąd wyskoczył w pliku, który znajduje się w zupełnie innym katalogu. Bez tej opcji nie moglibyśmy od razu do niego przeskoczyć.

    Dokładniej mówiąc %D oznacza, że Vim ma się spodziewać zmiany katalogu. Wraz z %D musi wystąpić %f w tej samej linii. %f określa miejsce, w którym pojawi się nowy katalog.

    Cała linijka mówi tyle, że gdy napotkasz wyrażenie make[jakakolwiek_liczba]: Wejście do katalogu `ścieżka' to wiedz, że zostały zmieniony aktualny katalog na ten w ścieżce.

  • Druga linijka jest analogiczna. %X oznacza opuszczenie katalogu i tak samo z %X w parze musi wystąpić %f.

  • Dwa ostatnie wzorce mówią dokładnie to samo, z tą tylko różnicą, że zamiast spodziewać się make[jakakolwiek_liczba] Vim może spodziewać się jakiegokolwiek ciągu liter i/lub liczb.

Kolejny upierdliwy problem (tym razem związany z programem make) polega na tym, że nie zawsze jesteśmy akurat w katalogu, który zawiera plik Makefile. I co wtedy? Wykonanie polecenia :make zakończy się komunikatem, że nie znaleziono pliku Makefile. Na szczęście program make posiada opcję -C która określa katalog, w którym znajduje się ten plik. Vim jest na tyle sprytny, że pozwala nam na przekazanie dowolnych parametrów do wykonywanego programu. Dla przykładu będąc w katalogu A i wiedząc, że plik Makefile znajduje się w katalogu wyżej możemy po prostu wywołać :make -C ..

Można sprawę jeszcze bardziej uprościć pisząc funkcję w Vimie, która sprawdzi gdzie jest plik Makefile i automatycznie uruchomi program make z odpowiednią opcją. Ale o tym może innym razem. Dodam jeszcze tylko, że listę błędów i ostrzeżeń po wykonaniu :make możemy wyświetlić za pomocą :copen i najeżdżając kursorem na odpowiednią linię oraz wciskając enter przejdziemy automatycznie do odpowiedniej linii w danym pliku.

To tyle na dziś. Miłego kodowania!

niedziela, 11 marca 2012

Vim Powerline

Czy nie zdarza się ci czasami zapomnieć w jakim trybie się aktualnie znajdujesz? Problem ten dotyczy zwłaszcza początkujących użytkowników ale i starszym się zdarza. Jest na to rada - plugin Powerline. Wygląda to tak, że każdy tryb ma swój własny kolor linii statusu, a do tego twórcy wtyczki zadbali o jej ładny wygląd. Tylko spójrz:
Prawda, że ładny?

To teraz do rzeczy. Instaluje się go nieco trudniej niż pozostałe pluginy ale idea jest ta sama. Możemy go wprost ściągnąć przez Vundle, o którym pisałem wcześniej lub po prostu użyć gita:

$ git clone https://github.com/Lokaltog/vim-powerline.git

Po czym kopiujemy pliki standardowo do katalogu ~/.vim.

Do pluginu jest dołączony skrypt o nazwie fontpatcher. Tworzy on dodatkowe znaki w czcionce, której używamy w gVimie. Uruchomienie tego skryptu na naszej czcionce jest niezbędne jeżeli chcemy mieć "trójkąty" w linii statusu. Bez tego będą to po prostu prostokąty o różnych kolorach (bez zakończenia trójkątnym znaczkiem).

Jeżeli chcemy użyć fontpatchera to robimy to w ten sposób:
1. Przechodzimy do katalogu ~/.fonts, gdzie powinna się znajdować czcionka, której używamy w gVimie. Jeżeli jej tam nie ma to ją tam kopiujemy.
2. Uruchamiamy skrypt:
$ /path/to/fontpatcher MyFontFile.ttf
3. Aktualizujemy cache czcionek:
$ sudo fc-cache -vf
4. Dorzucamy do pliku .vimrc linijkę:
let g:Powerline_symbols = 'fancy'
5. Upewniamy się, że plik cache został usunięty:
$ rm /tmp/Powerline.cache

To prawie wszystko. Pozostaje nam jedynie dodać jeszcze jedną opcję do ustawień Vima. Zatem otwieramy ponownie plik .vimrc i dopisujemy:
set laststatus=2
Bez ustawienia tej opcji, nasz pasek statusu byłby dostępny jedynie w momencie otwarcia co najmniej 2 okien (ang. split).

To tyle!

wtorek, 14 lutego 2012

Vundle

Ostatnio poszukiwałem dobrego managera pluginów do Vima. Głównie z tego względu, że mam ich co raz więcej oraz wiele z nich przestałem używać, a nadal leżą gdzieś w ~/.vim. Szukałem czegoś co pozwoliłoby mi nad nimi zapanować oraz potrafiło w łatwy sposób je aktualizować (nie śledząc w kółko www.vim.org).

Managerów dostępnych jest kilka. Na pierwszy ogień poszedł VAM. Niestety po kilku próbach się poddałem. Za każdym razem ściągał on pluginy bezpośrednio do katalogu domowego co mnie bardzo irytowało. Pewnie da się to skonfigurować ale nie miałem już ochoty na sprawdzanie źródeł, a w dokumentacji nic nie znalazłem.

Szukałem więc dalej. I tak przyszła pora na Vundle. Zainstalowałem zgodnie z instrukcją (dostępną na stronie pluginu) i od razu zabrałem się do instalowania moich ulubionych dodatków. Bardzo pomocna jest w tym momencie komenda :BundleSearch nazwa. Po jej wykonaniu dostajemy listę wtyczek podobnie "brzmiących" jak nazwa, którą wpisaliśmy. Wybierając kursorem linię z interesującym nas pluginem wciskamy klawisz i aby go zainstalować.


Jeżeli chcemy sobie zaktualizować dany plugin to wpisujemy :BundleInstall! nazwa, a jeżeli usunąć to :BundleClean nazwa.

Największą dla mnie zaletą jest to, że wpisując w pliku .vimrc Bundle 'nazwa' sprawiamy, że dany plugin jest wymagany, a co za tym idzie jeżeli go nie ma to zostanie automatycznie zainstalowany. W ten sposób ustawianie Vima na innej maszynie sprowadza się do przekopiowania pliku .vimrc oraz zainstalowania Vundle. Polecam!

wtorek, 10 stycznia 2012

O czystości języków programowania

Dzisiaj przybliżę nieco pojęcie czystości w odniesieniu do języków programowania, a później do samego Haskella. Określenia "czysty" używa się do dwóch typów języków: funkcyjnych oraz obiektowych. Zacznę może od tych drugich, gdyż jest to łatwiej wytłumaczyć.

Otóż czysty język obiektowy to taki, w którym każdy element języka jest albo obiektem, klasą albo metodą (czyli funkcją w klasie) albo atrybutem klasy (czyli zmienną w klasie). Co to oznacza w praktyce? Oznacza to tyle, że nawet instrukcja warunka if jest metodą w jakiejś klasie. Nie będę się nad tym dużo rozpisywał, podam jedynie, że przykładem takiego języka jest SmallTalk.

W językach funkcyjnych natomiast sprawa rozbija się o funkcje. Określenie danego języka językiem czysto funkcyjnym sugeruje, że każdy element języka jest funkcją. Co to oznacza? Oznacza to tyle, że funkcja jako argument przyjmuje funkcje a to sprawia, że nie możemy ich traktować jak zmienne (wyrażenie a :: Int nie jest zmienną tylko funkcją, która nie ma żadnych argumentów a zwraca typ Int). Nie możemy również tworzyć pętli, z uwagi na to, że w świecie funkcyjnym nie mamy kolejności wykonywania obliczeń. W związku z tym nie możemy obliczyć jednej rzeczy, a później przeskoczyć do linijki wyżej (funkcje potrzebne do obliczenia linijki wyżej mogły nie zostać jeszcze obliczone).

Jest jeszcze jeden aspekt najczęściej źle rozumiany. Funkcja nie może mieć efektów ubocznych. Co to są efekty uboczne? Ano są to niespodziewane rezultaty wykonania funkcji. Kluczowe jest słowo "niespodziewane". Na przykład weźmy sobie taką funkcję: toInt :: String -> Int. Zastanówmy się czego możemy się spodziewać po tej funkcji a czego nie. Patrząc po nazwie i jej typie spodziewamy się, że funkcja sparsuje sobie łańcuch znaków i zwróci liczbę jemu odpowiadającą. Nie spodziewamy się natomiast, że funkcja wykona zapytanie w bazie danych i zwróci wynik tego zapytania (np. "SELECT '123'::integer"). Niespodziewane jest również wypisanie czegoś na ekranie bądź narysowanie okienka czy cokolwiek innego. Zatem język czysty funkcyjnie nie powinien na to zezwalać.

Powszechne jest twierdzenie, że problem efektów ubocznych rozwiązano w Haskellu monadami. To nie do końca jest prawda. Za pomocą monad rozwiązano problem z IO, a nie same efekty uboczne jako takie. Przypuśćmy kontynuując przykład przytoczony powyżej, że chcielibyśmy napisać funkcję toIntDirty, która dokonywała by konwersji stringa na liczbę stosując zapytanie do bazy danych pokazane wyżej. Musielibyśmy więc sprawić aby patrząc nad typ tej funkcji spodziewalibyśmy się tej sytuacji. Trzeba więc to jakoś zaznaczyć. W Haskellu stosuje się w tym celu opakowanie danego typu w inny. Robi się to np. w taki sposób:

newtype Dirty a = Dirty a

Zatem nasza funkcja miała by typ toIntDirty :: String -> Dirty Int. Ktoś może zapytać co stoi na przeszkodzie aby stosować tą samą technikę w językach imperatywnych? Nic. Problem jest w tym, że kompilator tego na nas nie wymusi (bo język tego nie wymusza). Zauważmy, że funkcja, która wywołuje naszą funkcję toIntDirty musi również zaznaczyć, że podczas jej wykonania mogą się dziać "brudne" rzeczy. Haskell dlatego właśnie jest czystym językiem, gdyż można to wymusić. Dla jaśniejszej sytuacji weźmy taki kod w C:

typedef struct { int result; } DirtyInt;

DirtyInt toIntDirty (const char* text);

int toInt (const char* text)
{
    return toIntDirty(text).result;
} 

Ten kod jest w pełni legalny w C i nie ma możliwości aby wymusić na programiście, że funkcja toInt powinna zwracać DirtyInt, ponieważ w środku wykonuje "nieczystą" funkcję. W Haskellu natomiast, tak jak już to wspominałem, można wymusić aby programista nie mógł się "pozbyć" typu Dirty jak już go użyje. Robi się to tak:

module Type.Dirty where 
    (
      Dirty
    )

newtype Dirty a = Dirty a

Od teraz aby użyć typu Dirty musimy zaimportować moduł Type.Dirty. Zauważmy, że przy where nie napisałem Dirty(..) lecz Dirty. Zapis z kropkami powoduje wyeksportowanie wszystkich konstruktorów danego typu. Gdybym tak zrobił to legalny byłby zapis:

module Test where

import Type.Dirty

cleanDirty :: Dirty a -> a
cleanDirty (Dirty a) = a

a tego nie chcemy. W momencie jednak gdy nie ma tych kropek to powyższa funkcja się nie skompiluje. Tworzy to jednak kolejne problemy. Otóż pozostawiając to w ten sposób nie będziemy mogli wywołać żadnej "czystej" (mam tu na myśli bez typu Dirty) funkcji. Dla przykładu weźmy wspomnianą wcześniej funkcję toIntDirty, która zwraca typ Dirty Int. Chcielibyśmy teraz przemnożyć tego Inta przez, dajmy na to, liczbę 2. Nie da się. Nie zadziała np. coś takiego:

multiply :: Dirty Int -> Dirty Int
multiply a = a*2

ponieważ funkcja (*) nie działa na typie Dirty Int. Nie zadziała również to:

multiply2 :: Dirty Int -> Int
multiply2 (Dirty a) = a*2

z powodu wspomnianego wyżej (nie wyeksportowany konstruktor). Aby rozwiązać ten problem z pomocą przychodzą nam właśnie monady. Umożliwiają one dwie rzeczy. Po pierwsze pozwalają zachować kolejność obliczeń, a po drugie umożliwiają nam wywoływanie "czystych" funkcji na opakowanych typach. Monady reprezentowane są przez klasę Monad, której instancję sobie napiszemy do naszego typu Dirty:

module Type.Dirty where 
    (
      Dirty
    )

newtype Dirty a = Dirty a

instance Monad (Dirty a) where
    return a = Dirty a
    (Dirty a) >>= f = f a

Klasa Monad zawiera w sumie cztery funkcje ale do utworzenia instancji wystarczy tylko zdefiniować return oraz >>=. Funkcja return opakowuje zwykły typ w Dirty, np. return (10::Int) w naszym przypadku spowoduje utworzenie typu Dirty Int. Ciekawsza jest funkcja >>=. Ma ona typ Monad m => m a -> (a -> m b) -> m b co oznacza, że odpakowuje ona na chwilę z typu Dirty i przekazuje odpakowany typ (np. gdy mamy typ Dirty Int to odpakowany typ to Int) do funkcji f, a wynik tej funkcji musi być typu Dirty (ale nie koniecznie tego samego). W ten sposób możemy teraz napisać zdefiniować nasze mnożenie:

module Test where 

import Type.Dirty

toIntAndMultiplyDirty :: String -> Dirty Int
toIntAndMultiplyDirty text = toIntDirty text >>= return . (* 2)

W toIntAndMultiplyDirty tworzymy z tekstu liczbę i mnożymy ją przez 2 stosując w tym celu "czystą" funkcję (*). No dobrze, a w jaki sposób monady pozwalają osiągnąć zachowanie kolejności obliczeń? Bardzo prosto. Zauważmy, że w ciągu wywołań funkcji (>>=) każda funkcja po prawej stronie wymaga jako argumentu wyniku funkcji stojącej po lewej. Zatem zawsze zostanie wymuszone liczenie wartości wyrażenia zgodnie z kolejnością od lewej do prawej.

Wracając do IO, właśnie kolejność obliczeń była kluczowa. Wyobraźmy sobie, że chcemy wypisać dwie linijki jedna pod drugą. Gdyby typ IO nie był monadą wymuszającą kolejność wykonywania akcji to nie byłoby jasne i zgodne z intuicją, który napis wyświetli się jako pierwszy. Często natrafiałem na tezę, że funkcja nie jest czysta, ponieważ "kontaktuje się" ze światem zewnętrznym (np. wypisuje coś na ekranie). Otóż funkcja nie byłaby czysta, gdyby efekty jej wykonania były niespodziewane. Jeżeli jakaś funkcja zwraca typ IO to spodziewamy się, że kontaktuje się ona ze światem zewnętrznym, dokładnie tak samo spodziewamy się, że jak jakaś funkcja zwraca typ String to wykonuje ona operacje na łańcuchach znaków.