Zanieczyszczone języki tak naprawdę nie różnią się zasadniczo od bardziej znanych języków imperatywnych, zwłaszcza teraz, gdy skopiowano wiele sztuczek funkcjonalnych. Odmienny jest styl - sposób rozwiązywania problemów.
Niezależnie od tego, czy liczysz Haskella jako czysty, czy monadę IO jako nieczystość, styl Haskell jest ekstremalną formą tego stylu i warto się go nauczyć.
Monada IO Haskell wywodzi się z matematycznej teorii (oczywiście) monad. Jednak w przypadku programistów imperatywnych myślę, że powrót do monad ma większy sens.
Faza pierwsza - czysty język funkcjonalny może łatwo zwrócić dużą wartość ciągu. Ten duży ciąg może być kodem źródłowym programu imperatywnego, pochodzącego w sposób czysto funkcjonalny od niektórych parametrów określających wymagania. Następnie można zbudować kompilator „wyższego poziomu”, który uruchamia generator kodu, a następnie automatycznie podaje wygenerowany kod do kompilatora języka imperatywnego.
Faza druga - zamiast generować tekstowy kod źródłowy, generujesz silnie wpisane abstrakcyjne drzewo składniowe. Kompilator w języku imperatywnym jest wchłaniany do kompilatora „wyższego poziomu” i akceptuje AST bezpośrednio jako kod źródłowy. Jest to o wiele bliższe temu, co robi Haskell.
Jednak nadal jest to niezręczne. Na przykład masz dwa różne rodzaje funkcji - te oceniane podczas fazy generowania kodu i wykonywane podczas uruchamiania generowanego programu. To trochę jak rozróżnienie między funkcjami i szablonami w C ++.
Tak więc, dla fazy 3, uczyń obie te same - ta sama funkcja o tej samej składni może być częściowo oceniana podczas „generowania kodu”, lub w pełni oceniana, lub w ogóle nie oceniana. Ponadto należy odrzucić wszystkie zapętlone konstrukty AST na rzecz rekurencji. W rzeczywistości odrzuć ideę węzłów AST jako specjalnego rodzaju danych w ogóle - nie posiadaj węzłów AST o „wartości dosłownej”, tylko wartości itp.
To właśnie robi monada IO - operator bind jest sposobem komponowania „akcji” w celu tworzenia programów. To nic specjalnego - tylko funkcja. Wiele wyrażeń i funkcji można ocenić podczas „generowania kodu”, ale te, które zależą od efektów ubocznych I / O, muszą mieć ocenę opóźnioną do czasu wykonania - nie przez żadną specjalną regułę, ale jako naturalną konsekwencję zależności danych w wyrażenia.
Generalnie monady są po prostu uogólnieniem - mają ten sam interfejs, ale implementują operacje abstrakcyjne inaczej, więc zamiast ewaluować do opisu kodu imperatywnego, oceniają na coś innego. Posiadanie tego samego interfejsu oznacza, że istnieje kilka rzeczy, które możesz zrobić monadom, nie dbając o to, która monada, co okazuje się przydatne.
Ten opis bez wątpienia spowoduje eksplozję purystycznych głów, ale dla mnie wyjaśnia kilka prawdziwych powodów, dla których Haskell jest interesujący. Zaciera granicę między programowaniem a metaprogramowaniem i wykorzystuje narzędzia programowania funkcjonalnego do ponownego tworzenia imperatywnego programowania bez potrzeby specjalnej składni.
Krytykę, jaką mam szablony C ++, polega na tym, że są one rodzajem zepsutego czysto funkcjonalnego sublanguage w języku imperatywnym - aby ocenić tę samą podstawową funkcję w czasie kompilacji, a nie w czasie wykonywania, trzeba ją ponownie zaimplementować w zupełnie innym stylu kodowania. W Haskell, podczas gdy zanieczyszczenie musi być oznaczone jako takie w swoim typie, dokładnie ta sama funkcja może być oceniana zarówno w sensie metaprogramowania, jak i w trybie niemetaprogramowania w czasie wykonywania w tym samym programie - nie ma twardego wiersza między programowaniem a metaprogramowaniem.
To powiedziawszy, istnieją pewne rzeczy związane z metaprogramowaniem, których standardowy Haskell nie potrafi, głównie dlatego, że typy (i może kilka innych rzeczy) nie są pierwszorzędnymi wartościami. Istnieją jednak warianty językowe, które próbują rozwiązać ten problem.
Wiele rzeczy, które powiedziałem o Haskell, można zastosować w nieczystych językach funkcjonalnych - a czasem nawet w imperatywnych. Haskell jest inny, ponieważ nie masz innego wyjścia, jak przyjąć to podejście - w zasadzie zmusza Cię do nauki tego stylu pracy. Możesz „pisać C w ML”, ale nie możesz „pisać C w Haskell” - przynajmniej nie bez wiedzy o tym, co się dzieje pod maską.