Sposób, w jaki mi się to podoba, i to, co myślę, jest prawdą po tym, jak przez miesiąc pracowałem nad nauką Haskell, to fakt, że programowanie funkcjonalne zmienia twój mózg w interesujący sposób: zmusza cię do myślenia o znanych problemach na różne sposoby : zamiast pętli, myśl w mapach, fałdach i filtrach, itp. Ogólnie rzecz biorąc, jeśli masz więcej niż jedną perspektywę na problem, dzięki temu będziesz lepiej rozumieć ten problem i zmieniać punkty widzenia w razie potrzeby.
Inną fajną rzeczą w Haskell jest jego system typów. Jest ściśle wpisany na maszynie, ale silnik wnioskowania o typie sprawia, że czuje się jak program w Pythonie, który w magiczny sposób mówi ci, kiedy popełniłeś głupi błąd związany z typem. Komunikatów o błędach Haskella w tym względzie brakuje nieco, ale gdy lepiej zaznajomisz się z językiem, powiesz sobie: tak powinno być pisanie!
To przykład, który przekonał mnie, aby dowiedzieć się, Haskell (chłopiec i jestem zadowolony, zrobiłem).
OK, to krótki, czytelny program. W tym sensie jest lepszy niż program w C. Ale czym to się tak różni od (powiedzmy) programu w Pythonie o bardzo podobnej strukturze?
Odpowiedź to leniwa ocena. W większości języków (nawet niektórych funkcjonalnych) program o strukturze podobnej do powyższego spowodowałby załadowanie całego pliku do pamięci, a następnie ponowne zapisanie pod nową nazwą.
Haskell jest „leniwy”. Nie oblicza rzeczy, dopóki nie musi, a co za tym idzie , nie oblicza rzeczy, których nigdy nie potrzebuje. Na przykład, gdybyś usunął tę
writeFile
linię, Haskell nie zawracałby sobie głowy czytaniem czegokolwiek z pliku.W obecnej sytuacji Haskell zdaje sobie sprawę, że
writeFile
zależy odreadFile
, więc jest w stanie zoptymalizować tę ścieżkę danych.Chociaż wyniki są zależne od kompilatora, to zwykle dzieje się po uruchomieniu powyższego programu: program wczytuje blok (powiedzmy 8KB) pierwszego pliku, następnie zapisuje go w drugim pliku, a następnie odczytuje kolejny blok z pierwszego plik i zapisuje go w drugim pliku i tak dalej. (Spróbuj
strace
na nim biegać !)... co wygląda bardzo podobnie do tego, co zrobiłaby wydajna implementacja kopii pliku w C.
Tak więc Haskell umożliwia pisanie zwartych, czytelnych programów - często bez poświęcania dużej wydajności.
Kolejną rzeczą, którą muszę dodać, jest to, że Haskell po prostu utrudnia pisanie błędnych programów. Niesamowity system typów, brak efektów ubocznych i oczywiście zwartość kodu Haskell redukuje błędy z co najmniej trzech powodów:
Lepszy projekt programu. Mniejsza złożoność prowadzi do mniejszej liczby błędów logicznych.
Kompaktowy kod. Mniej wierszy, w których mogą występować błędy.
Błędy kompilacji. Wiele błędów po prostu nie jest poprawnych Haskell .
Haskell nie jest dla każdego. Ale każdy powinien spróbować.
źródło
hSetBuffering handle (BlockBuffering (Just bufferSize))
.Data.Bytestring.Lazy.readFile
), które nie mają nic wspólnego z Haskell jest leniwy (nie surowe) język. Monady sekwencjonują - oznacza to z grubsza, że „wszystkie skutki uboczne są wykonywane, gdy usuniesz wynik”. A jeśli chodzi o magię „leniwego Bajtestru”: jest to niebezpieczne i możesz to zrobić z podobną lub prostszą składnią w większości innych języków.readFile
również wykonuje leniwe IO w ten sam sposóbData.ByteString.Lazy.readFile
. Zatem odpowiedź nie jest zła i nie jest to jedynie optymalizacja kompilatora. Rzeczywiście, jest to część specyfikacji dla Haskell : „readFile
Funkcja czyta plik i zwraca zawartość pliku jako łańcuch. Plik jest czytany leniwie na żądanie, tak jak w przypadkugetContents
.”const fs = require('fs'); const [file1, file2] = process.argv.slice(2); fs.createReadStream(file1).pipe(fs.createWriteStream(file2))
. Bash ma też coś podobnego:cat $1 > $2
Zadajesz złe pytanie.
Haskell nie jest językiem, w którym patrzysz na kilka fajnych przykładów i mówisz "aha, teraz rozumiem, to jest to , co czyni go dobrym!"
To bardziej tak, że mamy wszystkie te inne języki programowania i wszystkie są mniej więcej podobne, a następnie jest Haskell, który jest zupełnie inny i zwariowany w sposób, który jest całkowicie niesamowity, gdy przyzwyczaisz się do tego zwariowania. Ale problem polega na tym, że przyzwyczajenie się do tego dziwactwa zajmuje trochę czasu. Rzeczy, które odróżniają Haskella od prawie każdego innego, nawet pół-głównego języka:
a także kilka innych aspektów, które różnią się od wielu języków głównego nurtu (ale są wspólne dla niektórych):
Jak odpowiedziały niektóre inne plakaty, połączenie wszystkich tych cech oznacza, że myślisz o programowaniu w zupełnie inny sposób. Dlatego trudno jest znaleźć przykład (lub zestaw przykładów), który odpowiednio zakomunikowałby to Joe-mainstreamowi-programista. To rzecz empiryczna. (Aby dokonać analogii, mogę pokazać zdjęcia z mojej podróży do Chin w 1970 roku, ale po obejrzeniu zdjęć nadal nie będziesz wiedział, jak to było mieszkać tam w tym czasie. Podobnie mogę pokazać Ci Haskell „quicksort”, ale nadal nie będziesz wiedział, co to znaczy być Haskellerem).
źródło
To, co naprawdę wyróżnia Haskell, to wysiłek włożony w jego projekt, aby wymusić programowanie funkcjonalne. Możesz programować w funkcjonalnym stylu w prawie każdym języku, ale zbyt łatwo jest porzucić przy pierwszej dogodności. Haskell nie pozwala na porzucenie programowania funkcjonalnego, więc musisz doprowadzić to do logicznego wniosku, który jest ostatecznym programem, o którym łatwiej jest myśleć i omija całą klasę najbardziej drażliwych typów błędów.
Jeśli chodzi o pisanie programu do użytku w świecie rzeczywistym, może się okazać, że Haskellowi brakuje pewnych praktycznych aspektów, ale ostateczne rozwiązanie będzie lepsze, jeśli najpierw poznałeś Haskella. Zdecydowanie jeszcze mnie tam nie ma, ale jak dotąd nauka Haskella była dużo bardziej pouczająca niż powiedzenie, że Lisp był na studiach.
źródło
unsafePerformIO
dla ludzi, którzy chcą tylko patrzeć, jak płonie świat;)Część zamieszania polega na tym, że czystość i statyczne typowanie umożliwiają równoległość w połączeniu z agresywnymi optymalizacjami. Języki równoległe są teraz popularne, a wielordzeniowy jest nieco uciążliwy.
Haskell oferuje więcej opcji równoległości niż prawie jakikolwiek inny język ogólnego przeznaczenia, wraz z szybkim, natywnym kompilatorem kodu. Naprawdę nie ma konkurencji z tego rodzaju obsługą stylów równoległych:
Jeśli więc zależy ci na tym, aby praca wielordzeniowa działała, Haskell ma coś do powiedzenia. Świetnym miejscem do rozpoczęcia jest samouczek Simona Peytona Jonesa dotyczący programowania równoległego i współbieżnego w Haskell .
źródło
Pamięć transakcyjna oprogramowania to całkiem fajny sposób radzenia sobie z współbieżnością. Jest znacznie bardziej elastyczny niż przekazywanie wiadomości i nie jest podatny na zakleszczenia jak muteksy. Implementacja STM w GHC jest uważana za jedną z najlepszych.
źródło
Spędziłem ostatni rok ucząc się Haskella i pisząc w nim dość duży i złożony projekt. (Projekt jest zautomatyzowanym systemem handlu opcjami, a wszystko, od algorytmów handlowych po analizę i obsługę niskopoziomowych, szybkich danych rynkowych, odbywa się w Haskell.) Jest znacznie bardziej zwięzły i łatwiejszy do zrozumienia (dla osób z odpowiednie tło) niż wersja Java, a także wyjątkowo solidne.
Prawdopodobnie największą wygraną dla mnie była możliwość modularyzacji przepływu sterowania przez takie rzeczy, jak monoidy, monady i tak dalej. Bardzo prostym przykładem może być monoid zamawiania; w wyrażeniu takim jak
gdzie
c1
i tak po powrocieLT
,EQ
alboGT
,c1
wracającEQ
powoduje ekspresję kontynuować, ocenyc2
; jeślic2
zwracaLT
lubGT
jest to wartość całości, ac3
nie jest obliczana. Tego rodzaju rzeczy stają się znacznie bardziej wyrafinowane i złożone w rzeczach takich jak monadyczne generatory wiadomości i parsery, w których mogę przenosić różne typy stanów, mieć różne warunki przerwania lub mogę chcieć być w stanie zdecydować dla dowolnego konkretnego połączenia, czy przerwanie naprawdę oznacza „brak dalszego przetwarzania” lub oznacza „zwracanie błędu na końcu, ale kontynuowanie przetwarzania w celu zebrania dalszych komunikatów o błędach”.To wszystko jest rzeczy, których nauczenie się zajmuje trochę czasu i prawdopodobnie sporo wysiłku, dlatego może być trudno przedstawić przekonujący argument na jego rzecz dla tych, którzy jeszcze nie znają tych technik. Myślę, że All About Monads samouczek daje całkiem imponującą demonstrację jednego aspektu tego, ale nie spodziewałbym się, że ktoś, kto nie jest zaznajomiony z materiałem, już go „zrozumie” przy pierwszym, a nawet trzecim, uważnym czytaniu.
W każdym razie w Haskell jest też wiele innych dobrych rzeczy, ale jest to główny, o którym nie wspominam tak często, prawdopodobnie dlatego, że jest dość złożony.
źródło
Ciekawy przykład można znaleźć pod adresem : http://en.literateprograms.org/Quicksort_(Haskell)
Co ciekawe, przyjrzyjmy się implementacji w różnych językach.
To, co sprawia, że Haskell jest tak interesujący, podobnie jak inne języki funkcjonalne, to fakt, że musisz inaczej myśleć o programowaniu. Na przykład generalnie nie będziesz używać pętli for ani while, ale użyjesz rekurencji.
Jak wspomniano powyżej, Haskell i inne języki funkcjonalne przodują w przetwarzaniu równoległym i pisaniu aplikacji do pracy na wielu rdzeniach.
źródło
Nie mogłem ci podać przykładu, jestem facetem od OCaml, ale kiedy jestem w takiej sytuacji jak ty, ciekawość po prostu się ogarnia i muszę pobrać kompilator / interpreter i spróbować. W ten sposób prawdopodobnie dowiesz się znacznie więcej o mocnych i słabych stronach danego języka funkcjonalnego.
źródło
Jedną z rzeczy, które uważam za bardzo fajne, gdy mam do czynienia z algorytmami lub problemami matematycznymi, jest nieodłączna leniwa ocena obliczeń przez Haskella, która jest możliwa tylko dzięki jej ściśle funkcjonalnej naturze.
Na przykład, jeśli chcesz obliczyć wszystkie liczby pierwsze, możesz użyć
a rezultatem jest nieskończona lista. Ale Haskell oceni to od lewej do prawej, więc dopóki nie spróbujesz zrobić czegoś, co wymaga całej listy, nadal możesz go używać bez utknięcia programu w nieskończoności, na przykład:
która sumuje wszystkie liczby pierwsze mniejsze niż 100. Jest to dobre z kilku powodów. Przede wszystkim muszę napisać tylko jedną funkcję pierwszą, która generuje wszystkie liczby pierwsze, a potem jestem prawie gotowy do pracy z liczbami pierwszymi. W języku programowania zorientowanego obiektowo potrzebowałbym jakiegoś sposobu, aby powiedzieć funkcji, ile liczb pierwszych powinna obliczyć przed zwróceniem, lub emulować zachowanie nieskończonej listy z obiektem. Inną rzeczą jest to, że generalnie piszesz kod, który wyraża to, co chcesz obliczyć, a nie w jakiej kolejności oceniać rzeczy - zamiast tego kompilator robi to za Ciebie.
Jest to przydatne nie tylko w przypadku nieskończonych list, w rzeczywistości jest używane bez Twojej wiedzy przez cały czas, gdy nie ma potrzeby oceniania więcej niż to konieczne.
źródło
Zgadzam się z innymi, że zobaczenie kilku małych przykładów nie jest najlepszym sposobem na pochwalenie się Haskellem. Ale i tak dam trochę. Oto błyskawiczne rozwiązanie problemów 18 i 67 Projektu Euler , które proszą Cię o znalezienie ścieżki o maksymalnej sumie od podstawy do wierzchołka trójkąta:
Oto pełna implementacja algorytmu BubbleSearch do wielokrotnego użytku autorstwa Lesh i Mitzenmacher. Użyłem go do spakowania dużych plików multimedialnych do archiwizacji na DVD bez odpadów:
Jestem pewien, że ten kod wygląda jak przypadkowy bełkot. Ale jeśli przeczytasz wpis na blogu Mitzenmachera i zrozumiesz algorytm, , że można spakować algorytm do kodu, nie mówiąc nic o tym, czego szukasz.
Podając kilka przykładów, o które prosiłeś, powiem, że najlepszym sposobem, aby zacząć doceniać Haskella, jest przeczytanie artykułu, w którym dostałem pomysły potrzebne do napisania pakowacza DVD: Why Functional Programming Matters autorstwa Johna Hughesa. Artykuł faktycznie poprzedza Haskell, ale znakomicie wyjaśnia niektóre pomysły, które sprawiają, że ludzie lubią Haskella.
źródło
Dla mnie atrakcją Haskella jest obietnica gwarantowanej przez kompilator poprawności. Nawet jeśli dotyczy to czystych części kodu.
Napisałem dużo kodu do symulacji naukowych i wiele razy zastanawiałem się , czy w moich poprzednich kodach był błąd, który mógłby unieważnić wiele bieżących prac.
źródło
Uważam, że w przypadku niektórych zadań jestem niesamowicie produktywny z Haskellem.
Powodem jest zwięzła składnia i łatwość testowania.
Oto jak wygląda składnia deklaracji funkcji:
To najprostszy sposób, w jaki mogę wymyślić definicję funkcji.
Jeśli napiszę odwrotność
Pisząc, mogę sprawdzić, czy jest to odwrotność dowolnego losowego wejścia
I dzwoniąc z linii poleceń
Który sprawdzi, czy wszystkie właściwości w moim pliku są zachowane, poprzez losowe testowanie danych wejściowych sto razy.
Nie sądzę, aby Haskell był idealnym językiem do wszystkiego, ale jeśli chodzi o pisanie małych funkcji i testowanie, nie widziałem nic lepszego. Jeśli twoje programowanie zawiera element matematyczny, jest to bardzo ważne.
źródło
Jeśli potrafisz owinąć głowę wokół systemu czcionek w Haskell, myślę, że sam w sobie jest to spore osiągnięcie.
źródło
nie ma konstrukcji pętli. niewiele języków ma tę cechę.
źródło
Zgadzam się z tymi, którzy mówili, że programowanie funkcjonalne przekręca twój mózg, aby patrzeć na programowanie z innej perspektywy. Używałem go tylko jako hobbysta, ale myślę, że zasadniczo zmieniło to sposób, w jaki podchodzę do problemu. Nie sądzę, żebym był prawie tak skuteczny z LINQ bez kontaktu z Haskellem (i używania generatorów i list składanych w Pythonie).
źródło
Mówiąc inaczej: Steve Yegge pisze, że językom Hindely-Milner brakuje elastyczności wymaganej do pisania dobrych systemów :
Haskella warto się nauczyć, ale ma on swoje słabości.
źródło