Zacząłem poważnie przyglądać się Lispowi w ten weekend (tzn. Uczyłem się tylko Lisp i nie wracam do projektów w C #) i muszę powiedzieć, że to uwielbiam. Zajmowałem się innymi językami funkcjonalnymi (F #, Haskell, Erlang), ale nie czułem remisu, który dał mi Lisp.
Teraz, gdy kontynuuję naukę Lisp, zacząłem się zastanawiać, dlaczego języki niefunkcjonalne nie obsługują funkcji najwyższej klasy. Wiem, że języki takie jak C # mogą robić podobne rzeczy z delegatami i do tego stopnia, że możesz używać wskaźników do funkcji w C / C ++, ale czy istnieje powód, dla którego nigdy nie stałoby się to funkcją w tych językach? Czy jest wadą uczynienie funkcji pierwszorzędnymi? Jest to dla mnie niezwykle przydatne, więc nie rozumiem, dlaczego więcej języków (poza paradygmatem funkcjonalnym) go nie implementuje.
[Edytuj] Doceniam dotychczasowe odpowiedzi. Ponieważ pokazano mi, że wiele języków obsługuje teraz funkcje najwyższej klasy, ponownie sformułuję pytanie, aby wyjaśnić, dlaczego ich wdrożenie zajmuje tyle czasu? [/Edytować]
Odpowiedzi:
C #, VB.NET, Python, JavaScript, teraz nawet C ++ 0x zapewnia funkcje najwyższej klasy.
Aktualizacja:
Wdrożenie zamknięć wymaga podnoszenia lambda - techniki pierwotnie zupełnie obcej dla programistów. Prawidłowe funkcje pierwszej klasy (w tym zamknięcia) wymagają co najmniej wsparcia ze strony środowiska wykonawczego i maszyny wirtualnej. Trochę czasu zajęło także zaadaptowanie starych technik funkcjonalnych do imperatywnego świata.
I najważniejsza część - funkcje pierwszej klasy są ledwo użyteczne, jeśli nie ma śmieci. Został wprowadzony do masowego programowania dopiero niedawno, z Javą, a tym samym z .NET. Oryginalne podejście Java polegało na nadmiernym uproszczeniu języka, tak aby był on zrozumiały dla przeciętnych programistów. Najpierw pojawił się .NET, a dopiero niedawno odszedł od tego (IMHO, całkiem uzasadnionego i odpowiedniego) kierunku.
Wszystkie takie koncepcje wymagają czasu, aby przemysł je przetworzył.
źródło
Funkcje pierwszej klasy są o wiele mniej interesujące bez zamknięć.
Zamknięcia nie są tak naprawdę możliwe bez pewnego dynamicznego zarządzania zakresem (odśmiecanie). Jedną z rzeczy, która sprawia, że C / C ++ jest tak wydajny, jest fakt, że o wiele łatwiej jest skompilować język, w którym ręcznie zarządzasz pamięcią, tak że w pewnym sensie C / C ++ jest poza równaniem.
I tak, jest kwestia wpływu OOP. Nie masz już oddzielenia metod i właściwości. Metody same w sobie są właściwościami, które akceptują funkcje jako wartości. W tym kontekście, co tak naprawdę oznacza przeciążenie metod, ponieważ w każdej chwili możesz po prostu wymieniać głupie rzeczy. Czy naprawdę możesz na przykład dodać to do Javy, nie wprowadzając istotnej zmiany paradygmatu na cały język? Gdzie jest umowa lub poczucie (fałszywe IMO) bezpieczeństwa, jakie ludzie uzyskują, wiedząc, że konstrukcja gwarantuje, że zawsze będzie działać tak samo za każdym razem? Rozsądne może być traktowanie funkcji powiązanych z obiektami jako metod jako odmiennego organizmu w językach, który pozwalał przede wszystkim na niezależne funkcjonowanie, ale w Javie nie jest tak naprawdę opcją.
W JavaScript, OOP i funkcjonalność są ze sobą ściśle powiązane i osobiście ciężko byłoby mi zobaczyć pierwszorzędne funkcje jako nic innego, jak tylko wbudowane w języki, w których nie były. Wymaga to jednak wielu innych zmian zmieniających paradygmat, w tym wysokiego poziomu zmienności obiektów i samych metod, a także możliwości wywoływania funkcji tak, jakby były członkami dowolnego obiektu w locie.
Języki to nie tylko zestawy narzędzi pełnych hickey do wykonywania zadań w większości. Są paradygmatami. Wiązki pomysłów, strategii i opinii, które są ze sobą powiązane w sposób, który jest połączony (lub wydaje się związany). W wielu przypadkach funkcje rzeczownika i czasownika tak naprawdę po prostu nie pasują do paradygmatu lub w najlepszym przypadku są niedoskonałe.
To powiedziawszy, czuję, że brakuje mi ramienia, gdy zmuszony jestem kodować bez nich.
źródło
To naprawdę nie jest niemożliwe. Ale to kolejna funkcja, a budżet na złożoność jest ograniczony. Może to zostać uznane przez projektanta języka za niepotrzebne (lub nawet nie przydarzyć się) - „dlaczego, do cholery, musielibyśmy przekazywać funkcje? Ten język służy do programowania systemu operacyjnego!”. Może także wymagać znacznego wysiłku, aby połączyć się z resztą języka. Na przykład typ funkcji może wymagać poważnych dodatków do systemu typów (np. W Javie), a nawet więcej, jeśli masz przeciążenie (dzięki @Renesis za wskazanie tego). Musisz także podać kod biblioteki, aby skorzystać z realnego - nikt nie chce się definiować
map
.Może to również utrudnić osiągnięcie innych celów języka:
f
nigdy nie jest przypisane ponownie, zanim wstawisz je.W tym samym duchu można zapytać, dlaczego jakikolwiek język programowania L1 nie ma funkcji F w zupełnie innym języku L2.
źródło
Myślę, że pierwszym problemem jest nieporozumienie, że obiektowo-funkcjonalne nie można mieszać. Szybka lista języków opisanych, przynajmniej przez Wikipedię, jako: JavaScript , ActionScript , Python , C # , F # .
Drugi problem wydaje się być definicją funkcji pierwszej klasy - dlaczego na przykład nie sądzisz, że C # je ma?
Nie jestem ekspertem od języków funkcjonalnych, więc jeśli się mylę, popraw mnie w komentarzach, ale rozumiem, że samo włączenie funkcji pierwszej klasy mniej więcej określa, czy język obsługuje paradygmat funkcjonalny .
Jakie jest prawdziwe pytanie?
Rozumiejąc, że języki zorientowane obiektowo mogą być również funkcjonalne, a te języki zawierają funkcje najwyższej klasy, brzmi to tak, jakbyś szukał pytania, dlaczego niektóre języki zorientowane obiektowo nie zawierają funkcji najwyższej klasy?
Przeciążenie funkcji
Jednym z głównych powodów tego jest trudność w zdefiniowaniu funkcji pierwszej klasy, gdy język wybrał również obsługę przeciążenia funkcji (przykład w Javie):
Do jakiej
dispatchEvent
funkcji odnosi się zmienna?Programowanie klasowe
Programowanie oparte na klasach nie uniemożliwia językom obsługi obiektów pierwszej klasy, ale może sprawić, że będzie bardziej mylące lub dodawać pytania, na które należy odpowiedzieć.
Na przykład ActionScript, jako język ECMAScript, zaczynał od znacznie bardziej funkcjonalnego paradygmatu, takiego jak JavaScript. Funkcje nie były z natury związane z obiektami, można je w zasadzie wywoływać z dowolnym obiektem, ponieważ ma on zasięg w momencie wykonywania.
Kiedy dodajesz (niedynamiczne) klasy, masz funkcje, które są z natury związane z instancją, a nie tylko samą klasą. To powoduje kilka zmarszczek w specyfikacji,
Function.apply
której tak naprawdę nie wykopałem, aby dowiedzieć się, jak sobie z tym poradzili.źródło
Zastanawiałem się nad tym samym. Kiedy jestem już w języku z lambdas, używam ich dużo. Nawet PHP staje się lepsze, gdy zdajesz sobie sprawę, że możesz zrobić zamknięcie z php 5.3 (nie jest tak przyjemne jak seplenienie, ale wciąż lepsze)
źródło