Czy system typów Haskell stanowi przeszkodę w zrozumieniu programowania funkcjonalnego? [Zamknięte]

33

Studiuję Haskell w celu zrozumienia programowania funkcjonalnego, oczekując, że zastosuję wgląd w innych językach (głównie Groovy, Python, JavaScript).

Wybrałem Haskell, ponieważ miałem wrażenie, że jest on bardzo czysto funkcjonalny i nie pozwala na poleganie na stanie.

Nie zdecydowałem się uczyć Haskell, ponieważ byłem zainteresowany nawigacją po wyjątkowo sztywnym systemie typów.

Moje pytanie brzmi: czy system silnego typu jest koniecznym produktem ubocznym niezwykle czystego języka funkcjonalnego, czy jest to wybór niezwiązany z projektem szczególnie dla Haskell?

Eric Wilson
źródło
6
Jeśli nie chcesz niczego wpisywać wprost, nie musisz niczego wpisywać jawnie. Haskell może samodzielnie wnioskować o typach. I to nie tak, że będziesz mieć jedną zmienną potencjalnie przechowującą dwa niezgodne typy.
Anon.
4
@Nie tak, ale twoje listy muszą być jednorodne. Zaufaj mi, tego rodzaju rzeczy mogą przeszkadzać, nawet przy wnioskowaniu typu.
Eric Wilson,
13
@FarmBoy i co jest nie tak z użyciem Może? Java naprawdę sprawia, że ​​używasz może na wszystkich klasach, co jest dziwne.
alternatywny
3
A jeśli naprawdę chcesz użyć listy heterogenicznej, możesz oczywiście użyć algebraicznych typów danych.
alternatywny
1
@mathepic w tym momencie naprawdę straciliśmy świadomość mojego pierwotnego pytania, które było całkowicie poprawnym pytaniem.
Eric Wilson,

Odpowiedzi:

40

Uważam, że zrozumienie systemu typu Haskell jest wzmacniaczem do zrozumienia programowania funkcjonalnego.

Rzecz w czysto funkcjonalnym programowaniu polega na tym, że przy braku efektów ubocznych, które pozwalają ci robić wszelkiego rodzaju rzeczy w sposób dorozumiany, czysto funkcjonalne programowanie sprawia, że ​​struktura twoich programów jest bardziej wyraźna.

Haskell zapobiega wsuwaniu rzeczy pod dywan, zmusza cię do jawnego radzenia sobie ze strukturą twojego programu i uczy cię języka do opisywania tych struktur: języka typów. Zrozumienie typów, szczególnie bogatych jak Haskell, sprawi, że będziesz lepszym programistą w dowolnym języku.

Gdyby Haskell nie był mocno wpisany, pojęcia takie jak monady, funktory aplikacyjne i tym podobne nigdy nie zostałyby zastosowane do programowania.

Waquo
źródło
2
To dobra odpowiedź, dodam, że chociaż system typów może początkowo wydawać się niezwykły, później, kiedy zaczniesz uczyć się bardziej zaawansowanych pojęć, zobaczysz, że są pewne rzeczy, które można zrobić tylko dzięki przestrzeganiu tego typu. system (dodaj STM i Data Parallel do powyższej listy). Rzeczy, które nie byłyby starterami w systemach innego typu, pasują naturalnie do systemu Haskell. Moja rada: trzymaj się tego przez jakiś czas, pozwól mu zatopić się w czasie (to nie jest język „tłokowy”).
anon
2
Wiem, że to bardzo stara odpowiedź, ale tak naprawdę się nie zgadzam. Wydaje mi się, że system tekstowy, chociaż niektóre wyrażenia mogą być jednoznaczne w języku, szczególnie w przypadku monad, takich jak State i Parsec, zamiata pod dywan mnóstwo ton rzeczy. To w rzeczywistości bardzo przeszkadza w mojej zdolności do uczenia się bibliotek języka.
Savanni D'Gerinel
4
@ SavanniD'Gerinel: Myślę, że w tej odpowiedzi „wsuwanie rzeczy pod dywan” nie oznacza dodawania ukrytej funkcjonalności (co Haskell kontroluje np. Za pomocą monad i która pomaga zredukować płytę kotłową), ale raczej pozwala na jakiś fragment kodu zrób coś, czego się nie oczekuje. Np .: czysta funkcja w Haskell nigdy nie będzie miała skutków ubocznych. Kropka. W wielu innych językach możesz to obiecać w dokumentacji funkcji, ale nic w twoim języku nie powstrzyma cię przed popchnięciem niektórych efektów ubocznych w twoim kodzie.
Giorgio
33

Najbardziej dynamicznie typowanym językiem funkcjonalnym jest zapewne Schemat. To powiedziawszy, system typu Haskell jest wskaźnikiem jego czystości. To pytanie „jak mierzyć czystość?”. System typów Haskell pozwala łatwo oddzielić nieczyste działania IO. Aby to zrobić, potrzebujesz systemu typu statycznego.

Powiedzmy jednak, że system typów Haskell nie ma nic wspólnego z programowaniem funkcjonalnym. Nadal byłoby szczytem pychy twierdzić, że system typów nie pomoże ci w tym przedsięwzięciu edukacyjnym. System typów Haskell jest bogaty i złożony, a tym bardziej interesujący w porównaniu do systemów typów C ++ i OCaml.

Czy to przeszkoda? Nie, myślę, że to atut. Spróbuj na przykład zastanowić się, jak poradzić sobie z lenistwem Haskella IO.

Logan Capaldo
źródło
8
+1 System typów Haskell może być twoim przyjacielem, gdy się przyzwyczaisz.
Larry Coleman
„Aby to zrobić, potrzebujesz systemu typu statycznego”. Naprawdę?
Jon Harrop,
1
„tym bardziej interesujące w porównaniu do systemów typów C ++ i OCaml”. Czy studiowałeś najwyższej klasy moduły wyższego rzędu OCaml i strukturalnie wpisanego wywnioskowanego systemu obiektowego i wariantów polimorficznych?
Jon Harrop,
2
@JonHarrop lub system efektów lub jakiś sposób pomiaru / oceny czystości. Tak, dlatego warto je porównać. Różne opcje dotyczą różnych języków.
Logan Capaldo,
20

Clojure jest dynamicznie pisany na maszynie i prawie tak czysty jak Haskell, więc istnieje dobry argument, że system typów Haskell był raczej wyborem projektowym niż absolutnym wymogiem. Oba zdecydowanie mają swoje mocne strony, więc możesz rozważyć Clojure, jeśli naprawdę nie lubisz sztywności Haskella (ale patrz poniżej).

Kiedy zacząłem używać Haskell, uważałem system typów za denerwujący i tolerowałem go tylko z powodu wnioskowania o typie. Wkrótce odkryłem, że wiele błędów typu kompilator narzekał na rzeczy, które i tak by nie działały, nawet gdyby kompilator pozwolił mi to zrobić (np. Przypadkowe użycie mapy zamiast concatMap). Potem odkryłem, że programy, które przeszły kontrolę typu, były zwykle poprawne lub przynajmniej bliskie poprawności. Miałem nawet leniwą fazę, w której dokonałem refaktoryzacji, zmieniając typ funkcji i pozwalając kompilatorowi powiedzieć mi, co jeszcze trzeba zmienić. W końcu zdałem sobie sprawę, że system typów Haskell był bardzo wyrazisty i zacząłem projektować moje programy wokół typów. To jest Święty Graal Haskell.

Larry Coleman
źródło
Kolejna rzecz do zapamiętania: nauczyłem się programowania funkcjonalnego, używając zarówno Scheme, jak i Haskell w tym samym czasie (pierwszy dla klasy, a drugi dla zabawy). Przekonałem się, że zrozumienie rekurencji było znacznie łatwiejsze dzięki dopasowaniu wzorców Haskella niż ifs i condsz Scheme, które, jak sądzę, przenosi się również na Clojure.
Tikhon Jelvis,
@ Larry Coleman: +1 za dokładne opisanie własnego doświadczenia z systemami typów: najpierw C ++, potem Ocaml, a teraz mój własny Felix. Tak, wciąż refaktoryzuję, ścigając błędy kompilatora.
Yttrill
8

System typów Haskell jest kluczem do jego zdolności do izolowania efektów od czystego kodu. O ile nie możesz izolować efektów w inny sposób lub nie usuniesz efektów całkowicie, silny system statyczny jest wymagany dla czysto funkcjonalnego programowania.

Haskell jest bardzo dobrym przykładem języka z silnym, statycznym systemem typów. Jeśli chcesz szerokiej i zaokrąglonej edukacji w zakresie informatyki, a zwłaszcza projektowania języków programowania, Haskell byłby doskonałym wyborem jako jeden z języków, których powinieneś się uczyć.

System typów nie powinien stanowić dużej przeszkody. Ludzie, którzy programują, często używają dynamicznych języków i przestrzegają konwencji pisania, które można kodować za pomocą systemu typów Haskell. Haskell oferuje również wnioskowanie o typie, które łagodzi gadatliwość w porównaniu do języków takich jak C ++ i Java. Gdy pojawi się komunikat o błędzie, kompilator informuje tylko w czasie kompilacji, co język z typami dynamicznymi powiedziałby w czasie wykonywania.

Przeciwieństwem dynamicznego systemu typów jest statyczny system typów, a nie silny system typów. System typu silnego jest przeciwieństwem systemu typu słabego.

dan_waterworth
źródło
1
Na przykład C jest statycznie, ale słabo wpisany. Masz typy, ale łatwo jest całkowicie obalić system typów, bawić się podstawowymi reprezentacjami specyficznymi dla maszyny itp. Wiele dynamicznie typowanych języków OTOH jest dość silnie typowanych - kilka niejawnych rzutów, kilka sposobów (jeśli w ogóle) obalenie systemu typów.
Steve314
4

Od razu powie ci, kiedy popełniasz głupie błędy. To jest pomocne. Pracowałem w Racket (Schemat) w ostatnim semestrze i wiele razy zdałem niezrozumiały s-exp, w którym spodziewałem się sparsowanego ast do jakiejś funkcji w moim tłumaczu, i to pokazało się tylko w moim średniej wielkości zestaw testowy. Gdybym miał jakieś statyczne pisanie, natychmiast zwróciłbym na to uwagę.

Oczywiście, błędy logiczne nie mogą być naprawdę wychwycone przez system typów, ale liczba sposobów, w które można zepsuć, jest znacznie zmniejszona.

Wnioskowanie typu pozwala również zignorować system typów, jeśli chcesz. Nadal tam jest, ale nie wymaga aktywnego wkładu z twojej strony. Nadal pomocne jest zrozumienie typów funkcji, ale poprawny kod będzie działał dobrze.

Czystość Haskella jest zakodowana w systemie typów. Monada IO jest konstrukcją na poziomie typu, która zatrzymuje wyciekanie nieczystego kodu do czystych funkcji, więc czystość jest gwarantowana przez system typów.

Theo Belaire
źródło
8
Jeśli uważasz, że możesz zignorować system typów Haskella, to myślę, że nie kodowałeś zbyt wiele Haskell.
Eric Wilson,
Nie ignoruj ​​tyle, ile ignoruj, tylko wypisz funkcję, załaduj ją do GHCi i uruchom: t. Ale nadal będziesz musiał czasami spryskać niektóre funkcje zintegrowane lub inne.
Theo Belaire,
1
Tyr, nawet z wnioskowaniem typu, 90% używania i kodowania funkcji Haskell sprawia, że ​​te cholerne rzeczy łączą się ze sobą, co wymaga zrozumienia jego systemu czcionek i tajemniczych komunikatów o błędach sprawdzania typu. Nawet „: t” nie jest magicznym rozwiązaniem, to tylko pierwszy krok do zrozumienia, jak kompilować program.
Andres F.,
Cóż, niektóre części są nieporządne, zgadzam się. Naprawdę uważam, że elementy liczbowe w preludium mogłyby zostać oczyszczone i naprawione, ponieważ w obecnej postaci jest to straszny bałagan. Ale większość kluczowych aspektów funkcjonalnych jest dość czysta. map, filter, foldr / l i inne zabawne funkcje funkcjonalne działają całkiem nieźle.
Theo Belaire,
2

Bycie „funkcjonalnym” językiem oznacza (oprócz innych rzeczy), że funkcje są pierwszorzędnymi obiektami w tym języku.

Bycie „czystym” językiem oznacza, że ​​funkcje są funkcjami matematycznymi (w przeciwieństwie do procedur) - przy tych samych danych wejściowych zawsze dają takie same wyniki.

„Czysty język funkcjonalny” to taki, w którym trzymają się oba powyższe. Nic mi nie wiadomo o „wyłącznie przy pomocy ly języku funkcjonalnej”.

System silnego typu to jeden czysty sposób na uzyskanie czystego, ale praktycznego języka. Typy pomagają kompilatorowi w określaniu optymalizacji, oprócz dalszego zapewniania poprawności. (Ale to nie jedyny sposób - clojure jest czysty, ale nie ma tak silnego systemu typów jak Haskell.)

Jeśli przeszkadza Ci system typów, sugeruję wypróbowanie bardziej dynamicznego języka, takiego jak Scheme, lub skorzystanie z systemu wnioskowania typu Haskell.

pyNem
źródło
0

Tak, system typów jest niesamowitym atutem. Bardzo trudno byłoby nawet opisać, jak działają monady lub jak działają niektóre kombinatory bez systemu typów. Zastanów się, ile samouczków na temat Haskell najpierw poprosi cię o rozważenie rodzaju omawianej funkcji za pomocą: t na REPL. Jest to po prostu niedostępne w dynamicznie pisanym języku. Jasne, cała złożoność systemu typów wciąż istnieje. Monada wciąż jest monadą. Ale język postanowił umyć ręce i nie udzielić żadnej pomocy. Jesteś sam, kolego. Nie pukam dynamicznie pisanych języków. Bardzo ich kocham. Schemat jest par excellance elektronarzędzi. Ale zauważysz, że kiedy mówimy o rzeczach takich jak monady w dynamicznych językach, często wymyślamy zapisdo opisu rodzaju procedur. Funkcjonalny programista będzie walczył z typami w taki czy inny sposób. Narzędzie do sprawdzania typu Haskell zapewnia tylko dobre narzędzia do nauczenia się, jak to zrobić.

Ara Vartanian
źródło