Co spowodowało popularność funkcji lambda we współczesnych językach programowania głównego nurtu?

112

W ciągu ostatnich kilku lat anonimowe funkcje (funkcje AKA lambda) stały się bardzo popularnym konstruktem językowym i prawie każdy główny / główny język programowania wprowadził je lub planuje wprowadzić w nadchodzącej rewizji standardu.

Jednak anonimowe funkcje są bardzo starą i bardzo dobrze znaną koncepcją matematyki i informatyki (wymyśloną przez matematyka Alonzo Church około 1936 r. I używaną przez język programowania Lisp od 1958 r., Patrz np. Tutaj ).

Dlaczego więc dzisiejsze główne języki programowania (z których wiele pochodzi od 15 do 20 lat temu) od samego początku nie obsługiwały funkcji lambda i wprowadziły je dopiero później?

A co spowodowało masowe przyjęcie anonimowych funkcji w ciągu ostatnich kilku lat? Czy istnieje jakieś szczególne zdarzenie, nowe wymaganie lub technika programowania, która zapoczątkowała to zjawisko?

WAŻNA UWAGA

Celem tego pytania jest wprowadzenie anonimowych funkcji we współczesnych językach głównego nurtu (a zatem, z kilkoma wyjątkami, niefunkcjonalnych) językach. Zauważ też, że anonimowe funkcje (bloki) są obecne w Smalltalk, który nie jest językiem funkcjonalnym, i że normalnie nazwane funkcje są obecne nawet w językach proceduralnych, takich jak C i Pascal, od dłuższego czasu.

Nie przesadzaj z generalizacją swoich odpowiedzi, mówiąc o „przyjęciu paradygmatu funkcjonalnego i jego zaletach”, ponieważ nie jest to przedmiotem pytania.

Giorgio
źródło
7
15-20 lat temu ludzie zadawali to samo pytanie o OO ... to nie była nowa koncepcja, ale miała eksplozję popularności.
MattDavey,
7
@MattDavey Most na pewno by się nie zgodził, ale musiałbym im przypomnieć, że „większość programistów Smalltalk” nie jest tak wieloma ludźmi; P
yannis
30
Myślę, że bardziej interesujące jest pytanie, co spowodowało ich śmierć ! Po tym wszystkim, że był czas, kiedy większość współczesnych języków nie ma lambdy, a następnie w językach takich jak Java i C ++ stał się popularny. (Chociaż nie nazwałbym dokładnie Java „nowoczesnym” językiem. Najnowszą koncepcją w Javie jest Generics, która pochodzi z końca lat 60. / wczesnych 70. Nawet kombinacja funkcji Java zapewnia bezpieczeństwo wskaźnika, bezpieczeństwo pamięci, typ bezpieczeństwo, GC, statycznie wpisane OO, Generics wszystkie istniały na Eiffelu w 1985… i znacznie lepiej, IMHO.)
Jörg W Mittag
31
Nawet zanim pojawiła się Java 1.0, gdy była jeszcze na wczesnym etapie projektowania, prawie wszyscy wskazywali, że Java potrzebuje lambd. Niektórzy projektanci, którzy pracowali nad Javą, to Guy Steele (zwolennik Lisp, współautor Scheme, współautor Common Lisp, projektant Fortress), James Gosling (napisał pierwszy interpreter Emacsa Lispa na komputery PC), Gilad Bracha (Smalltalk rzecznik, współtwórca Animorphic Smalltalk, projektant Newspeak), Phil Wadler (współtwórca Haskell), Martin Odersky (projektant Scala). To, jak Java skończyła bez lambdów, jest naprawdę poza mną.
Jörg W Mittag
8
„Mały kawałek” często oznacza 50% funkcji, 50% hałasu.
kevin cline

Odpowiedzi:

86

Z pewnością zauważalny jest trend w kierunku programowania funkcjonalnego lub przynajmniej niektórych jego aspektów. Niektóre popularne języki, które w pewnym momencie przyjęły funkcje anonimowe to C ++ ( C ++ 11 ), PHP ( PHP 5.3.0 ), C # ( C # v2.0 ), Delphi (od 2009), Objective C ( bloki ) podczas Java 8 przyniesie wsparcie dla lambdas w języku . Są też popularne języki, które na ogół nie są uważane za funkcjonalne, ale obsługiwane anonimowe funkcje od samego początku lub przynajmniej na początku, czego świetnym przykładem jest JavaScript.

Podobnie jak w przypadku wszystkich trendów, próba znalezienia jednego zdarzenia, które je wywołało, jest prawdopodobnie stratą czasu, zwykle jest to kombinacja czynników, z których większość nie jest wymierna. Praktyczny Common Lisp , opublikowany w 2005 roku, mógł odegrać ważną rolę w zwróceniu uwagi na Lisp jako język praktyczny , ponieważ przez dłuższy czas Lisp był głównie językiem, który można spotkać w środowisku akademickim lub na bardzo specyficznych niszowych rynkach. Popularność JavaScript mogła również odegrać ważną rolę w zwróceniu uwagi na anonimowe funkcje, jak to wyjaśnia wspaniała odpowiedź .

Oprócz przyjęcia koncepcji funkcjonalnych z języków wielofunkcyjnych, zauważalne jest także przejście do języków funkcjonalnych (lub głównie funkcjonalnych). Języki takie jak Erlang (1986), Haskell (1990), OCaml (1996), Scala (2003), F # (2005), Clojure (2007), a nawet języki specyficzne dla domeny, takie jak R (1993), wydają się zyskać silną pozycję po ich wprowadzeniu. Ogólny trend zwrócił nową uwagę na starsze języki funkcjonalne, takie jak Scheme (1975) i oczywiście Common Lisp.

Myślę, że najważniejszym wydarzeniem jest przyjęcie programowania funkcjonalnego w branży. Absolutnie nie mam pojęcia, dlaczego tak się nie stało, ale wydaje mi się, że w pewnym momencie na początku i w połowie lat 90. funkcjonalne programowanie zaczęło znajdować swoje miejsce w branży, zaczynając (być może) od rozprzestrzeniania się Erlanga w telekomunikacja i przyjęcie Haskell w branży lotniczej i projektowaniu sprzętu .

Joel Spolsky napisał bardzo interesujący post na blogu, The Perils of JavaSchools , w którym opowiada się przeciwko (ówczesnemu) trendowi uniwersytetów, by faworyzować Javę nad innymi, być może trudniejszymi do nauki językami. Chociaż post na blogu ma niewiele wspólnego z programowaniem funkcjonalnym, wskazuje na kluczowy problem:

Na tym polega debata. Lata bicia przez leniwych studentów CS, takich jak ja, w połączeniu ze skargami ze strony przemysłu na temat tego, że niewielu kierunków CS kończy studia na amerykańskich uniwersytetach, odbiło się na skutkach, aw ostatniej dekadzie wiele innych doskonale dobrych szkół przeszło w 100% na Javę. To jest modne, rekruterzy, którzy używają „grep” do oceny CV wydają się to lubić, a co najważniejsze, nie ma nic tak trudnego w Javie, aby naprawdę wyeliminować programistów bez części mózgu, która wykonuje wskaźniki lub rekurencję, więc wskaźniki rezygnacji są niższe, a działy informatyki mają więcej studentów i większe budżety - i wszystko jest w porządku.

Nadal pamiętam, jak bardzo nienawidziłem Lisp, kiedy pierwszy raz ją spotkałem podczas studiów. To zdecydowanie surowa kochanka i nie jest to język, w którym można od razu być produktywnym (cóż, przynajmniej ja nie mogłem). W porównaniu do Lispa, Haskell (na przykład) jest znacznie bardziej przyjazny, możesz być produktywny bez większego wysiłku i bez poczucia się jak kompletny idiota, a to może być również ważnym czynnikiem w przejściu na programowanie funkcjonalne.

W sumie to dobra rzecz. Kilka języków wielozadaniowych przyjmuje koncepcje paradygmatu, które mogły wydawać się tajemnicze dla większości ich użytkowników, a przepaść między głównymi paradygmatami się zmniejsza.

Powiązane pytania:

Dalsza lektura:

Yannis
źródło
Dzięki za odpowiedź (i wiele ciekawych pomysłów). +1 Jednak argumentowałbym, że wprowadzenie (tylko) lambd do języka programowania jest bardzo małym krokiem w kierunku FP, i może być nawet mylące dla wielu (co lambdas robią same w języku imperatywnym?). Po nauce Haskell, Scali i SML nie mam poczucia, że ​​mogę robić prawdziwy FP z imperatywnym językiem, który obsługuje tylko lambdy (co z curry i dopasowywaniem wzorów, niezmiennością?).
Giorgio
2
@YannisRizos: Perl miał anonimowe funkcje od pierwszego wydania 5 (1994), ale nie były całkowicie „właściwe” aż do 5.004 (1997).
Blrfl,
1
@penartur Tak też myślałem, ale przyjazny edytor poprawił mnie, wskazując mnie tutaj: msdn.microsoft.com/en-us/library/0yw3tz5k%28v=vs.80%29.aspx
yannis
Myślę, że być może głównym „wydarzeniem”, które wywołało popularność języków funkcjonalnych, jest Internet. Mówiąc dokładniej, przejście z programów komputerowych na stronę serwera. Daje to twórcy swobodę wyboru dowolnego języka programowania. Paul Graham i Lisp w latach 90. są godnym uwagi przykładem.
Gilad Naor,
32

Myślę, że interesujące jest to, jak bardzo popularność programowania funkcjonalnego zrównoważyła wzrost i rozpowszechnianie Javascript. JavaScript ma wiele radykalnych cech w spektrum programowania funkcjonalnego, które w momencie jego tworzenia (1995) nie były zbyt popularne wśród głównych języków programowania (C ++ / Java). Został nagle wprowadzony do głównego nurtu jako jedyny język programowania WWW po stronie klienta. Nagle wielu programistów po prostu musiało znać Javascript, dlatego musieliście wiedzieć o funkcjonalnych funkcjach języka programowania.

Zastanawiam się, jak popularne byłyby języki / funkcje funkcjonalne, gdyby nie nagły wzrost Javascript.

Doug T.
źródło
5
Javascript jest z pewnością ważnym językiem, ale nie jestem pewien, czy wprowadzenie Javascript może samodzielnie tłumaczyć popularność programowania funkcjonalnego: w ciągu ostatnich lat pojawiło się wiele innych funkcjonalnych języków programowania, jak zilustrował to Yannis w swojej odpowiedzi .
Giorgio
8
@Giorgio - mogło istnieć wiele innych funkcjonalnych języków programowania, ale (stosunkowo) nikt ich nie używa. Korzystanie z JS i zwiększony pogląd, że sposób tworzenia funktorów w C ++ / Java jest bolesny i irytujący, jest tak naprawdę siłą napędową głównego nurtu, nawet jeśli bardziej akademickie języki ugruntowały sposób ich implementacji.
Telastyn
1
Popularność języków dynamicznych jest ogólnie wskazana jako jedno z wyjaśnień popularności Haskell: book.realworldhaskell.org/read/…
yannis
Ponadto pytanie nie koncentruje się na popularności FP, ale na późnym wprowadzeniu anonimowych funkcji w niefunkcjonalnych językach ogólnego przeznaczenia. Nawet jeśli duża publiczność (większość programistów) ich nie znała, projektanci języków znali ich bardzo dobrze. Musiał istnieć powód, aby je pominąć na początku. Może zostały uznane za nieintuicyjne dla twórców wczesnych lat 90-tych.
Giorgio
@giorgio - Ich implementacja jest znacznie trudniejsza niż funktorów w stylu Java. W połączeniu z brakiem wiedzy / adopcji jest to dość jasny wybór projektu.
Telastyn
27

JavaScript i DOM obsługi zdarzeń sprawiły, że miliony programistów musiał nauczyć się przynajmniej trochę o funkcji pierwszej klasy w tym celu dowolny interaktywność w internecie.

Stamtąd jest to stosunkowo krótki krok do anonimowych funkcji. Ponieważ JavaScript się nie zamyka this, zdecydowanie zachęca również do zapoznania się z zamknięciami. A potem jesteś złoty: rozumiesz anonimowe funkcje pierwszej klasy, które zamykają się wokół obejmujących zakresy leksykalne.

Gdy czujesz się komfortowo, potrzebujesz go w każdym używanym języku.

hojny
źródło
7
+1 to nie tylko anonimowe funkcje. Zamknięcia są znacznie szerszym pojęciem niż tylko zdefiniowanie funkcji tymczasowej.
phkahler
@phkahler: Masz rację iw tym sensie Java ma już zamknięcia (i nawet potężniejsze niż to, co otrzymujesz z literału funkcji), ale brakuje jej zwięzłej notacji dla typowego przypadku anonimowej klasy.
Giorgio
17

Z pewnością nie jest to jedyny czynnik, ale zwrócę uwagę na popularność Ruby. Nie mówię, że jest to ważniejsze niż jakakolwiek z sześciu odpowiedzi już na tablicy, ale myślę, że wiele rzeczy wydarzyło się jednocześnie i że warto je wszystkie wymienić.

Ruby nie jest językiem funkcjonalnym, a jego lambdas, dźgnięcia i bloki wydają się nieporadne, gdy użyłeś czegoś takiego jak ML, ale w rzeczywistości spopularyzował pojęcie mapowania i zredukowania do pokolenia młodych programistów uciekających z Javy i PHP dla hippera pastwiska. Lambdy w kilku językach wydają się bardziej defensywnymi ruchami niż cokolwiek innego („Trzymaj się! Też mamy !!”)

Ale składnia bloku i sposób jej integracji z .each, .map, .reduce i tak dalej upowszechniły ideę anonimowej funkcji, nawet jeśli jest to naprawdę konstrukcja składniowa, która zachowuje się jak coroutine. A łatwa konwersja do proc poprzez i sprawia, że ​​jest to lek bramkowy do programowania funkcjonalnego.

Twierdzę, że programiści Ruby on Rails piszący JavaScript byli już włączeni do robienia rzeczy w lekkim, funkcjonalnym stylu. Połącz to z programowaniem blogów, wynalazkiem Reddit, wiadomościami hakerów i przepełnieniem stosu mniej więcej w tym samym czasie, a pomysły rozprzestrzeniają się szybciej w Internecie niż w czasach grup dyskusyjnych.

TL; DR: Ruby, Rails, JavaScript, blogowanie i Reddit / Hacker News / Stack Overflow wypchnęły funkcjonalne pomysły na masowy rynek, więc wszyscy chcieli je w istniejących językach, aby zapobiec dalszym wadom.

Reg Braithwaite
źródło
2
+1 Za dobrą odpowiedź i (gdybym mógł, bo mam tylko jedną opinię) +1 za wskazanie, że „Lambdy w kilku językach wydają się bardziej defensywnymi ruchami niż cokolwiek innego („ Trzymaj się! Mamy te też !!) ”. Myślę, że jest to również istotny czynnik. W przypadku niektórych języków lambdas to miła w obsłudze funkcja, która, choć dodaje bardzo niewielkiej mocy ekspresyjnej całemu językowi, daje mu pewną popularność ( wydaje się, że wielu programistów uważa, że ​​wsparcie dla funkcji anonimowych jest równoważne z pełnym wsparciem dla programowania funkcjonalnego)
Giorgio
2
Naprawdę uważam, że to jest powód, dla którego większość języków zaimplementowała składnię bloków w ostatnich latach. Ale jedynym sposobem, aby się upewnić, jest zapytanie twórców języka, jakie były ich motywy. Możemy tylko spekulować imo.
SpoBo,
dla mnie Ruby jest językiem, który jako pierwszy sprawił, że bloki są rockowe i bardzo atrakcyjne, więc +1. Haskell mógł mieć również wpływ.
rogerdpack,
13

Jak zauważył Yannis , istnieje wiele czynników, które wpłynęły na przyjęcie funkcji wyższego rzędu w językach, w których wcześniej nie było. Jednym z ważnych elementów, które dotknął jedynie lekko, jest rozprzestrzenianie się procesorów wielordzeniowych, a wraz z tym pragnienie bardziej równoległego i równoległego przetwarzania.

Styl mapowania / filtrowania / zmniejszania programowania funkcjonalnego jest bardzo przyjazny dla równoległości, umożliwiając programistom łatwe korzystanie z wielu rdzeni bez pisania wyraźnego kodu wątkowego.

Jak zauważa Giorgio, funkcjonalne programowanie to coś więcej niż tylko funkcje wyższego rzędu. Funkcje oraz mapa / filtr / redukcja wzorca programowania i niezmienność są rdzeniem programowania funkcjonalnego. Razem te rzeczy tworzą potężne narzędzia programowania równoległego i współbieżnego. Na szczęście wiele języków obsługuje już pewne pojęcie niezmienności, a nawet jeśli nie, programiści mogą traktować rzeczy jako niezmienne, umożliwiając bibliotekom i kompilatorowi tworzenie i zarządzanie operacjami asynchronicznymi lub równoległymi.

Dodanie funkcji wysokiego rzędu do języka jest ważnym krokiem do uproszczenia programowania współbieżnego.

Aktualizacja

Dodam kilka bardziej szczegółowych przykładów, aby odpowiedzieć na obawy Loki.

Rozważ następujący kod C #, który przegląda kolekcję widżetów, tworząc nową listę cen widżetów.

List<float> widgetPrices;
    float salesTax = RetrieveLocalSalesTax();
foreach( Widget w in widgets ) {
    widgetPrices.Add( CalculateWidgetPrice( w, salesTax ) );
}

W przypadku dużej kolekcji widżetów lub intensywnej obliczeniowo metody CalculateWidgetPrice (Widget) ta pętla nie wykorzysta dobrze dostępnych rdzeni. Wykonanie obliczeń cen dla różnych rdzeni wymagałoby od programisty jawnego tworzenia wątków i zarządzania nimi, przekazywania pracy i zbierania wyników razem.

Rozważ rozwiązanie po dodaniu funkcji wysokiego rzędu do C #:

var widgetPrices = widgets.Select( w=> CalculateWidgetPrice( w, salesTax ) );

Pętla foreach została przeniesiona do metody Select, ukrywając szczegóły jej implementacji. Jedyne, co pozostaje dla programisty, to powiedzieć Wybierz, jaką funkcję zastosować do każdego elementu. Pozwoliłoby to implementacji Select na uruchamianie obliczeń w trybie parellel, zajmując się wszystkimi problemami z synchronizacją i zarządzaniem wątkami bez udziału programisty.

Ale oczywiście Select nie wykonuje swojej pracy równolegle. Tam właśnie pojawia się niezmienność. Implementacja Select nie wie, że podana funkcja (powyżej CalculateWidgets) nie ma skutków ubocznych. Funkcja może zmienić stan programu poza widokiem Select i jego synchronizacją, psując wszystko. Na przykład w tym przypadku wartość saleTax może zostać zmieniona przez pomyłkę. Czyste języki funkcjonalne zapewniają niezmienność, więc funkcja Wybierz (mapa) może mieć pewność, że żaden stan się nie zmienia.

C # rozwiązuje ten problem, dostarczając PLINQ jako alternatywę dla Linq. To wyglądałoby jak:

var widgetPrices = widgets.AsParallel().Select(w => CalculateWidgetPrice( w, salesTax) );

Który w pełni wykorzystuje wszystkie rdzenie twojego systemu bez wyraźnego zarządzania tymi rdzeniami.

Ben
źródło
Wskazuję na potrzebę bardziej równoległego i równoczesnego przetwarzania, jest to omówione w artykule ACM „Historia Erlanga”, do którego odsyłam w czwartym akapicie. Ale to bardzo dobra uwaga i prawdopodobnie powinienem był ją nieco rozwinąć. +1, ponieważ teraz nie muszę; P
yannis
Masz rację, nie wyglądałem wystarczająco uważnie. Zredagowałem moją uwagę.
Ben
Och, tak naprawdę nie musieliście tego robić, nie narzekałem;)
yannis
4
Żadne z wyżej opisanych elementów nie wymaga lambdas. Tę samą funkcjonalność uzyskuje się równie łatwo dzięki nazwanym funkcjom. Tutaj po prostu dokumentujesz causei perceived affectbez wyjaśniania correlation. Ostatnie zdanie IMO dotyczy tego pytania; ale nie odpowiedziałeś na to. Dlaczego upraszcza programowanie współbieżne.
Martin York,
@Ben: Uważaj, aby twój przykład dotyczy funkcji wyższego rzędu, które nie wymagają użycia funkcji anonimowych. Twoja odpowiedź zawiera ciekawe pomysły (na inne pytanie), ale obecnie nie wchodzi w grę.
Giorgio
9

Zgadzam się z wieloma odpowiedziami tutaj, ale ciekawe jest to, że kiedy dowiedziałem się o lambdach i wskoczyłem na nie, nie było to z żadnego powodu, o którym wspominali inni.

W wielu przypadkach funkcje lambda po prostu poprawiają czytelność kodu. Przed lambdami, kiedy wywołujesz metodę, która zaakceptowała wskaźnik funkcji (lub funkcję, lub delegację), musiałeś zdefiniować treść tej funkcji gdzieś indziej, więc kiedy miałeś konstrukcję „foreach”, twój czytelnik musiałby przejść do innego część kodu, aby zobaczyć, co dokładnie planujesz zrobić z każdym elementem.

Jeśli treść funkcji przetwarzającej elementy zawiera tylko kilka wierszy, użyłbym funkcji anonimowej, ponieważ teraz, gdy czytasz kod, funkcjonalność pozostaje niezmieniona, ale czytnik nie musi przeskakiwać tam iz powrotem, cała implementacja jest tuż przed nim.

Wiele technik programowania funkcjonalnego i równoległości można by osiągnąć bez anonimowych funkcji; po prostu zadeklaruj zwykły i podaj odniesienie do tego, ilekroć potrzebujesz. Ale dzięki lambdas znacznie poprawiono łatwość pisania kodu i łatwość odczytu kodu.

DXM
źródło
1
Bardzo dobre wyjaśnienie (+1). Programiści Lisp zdają sobie z tego sprawę od 1958 roku; ;-)
Giorgio
4
@Giorgio: Jasne, ale programiści lisp musieli także kupić specjalne klawiatury ze wzmocnionymi klawiszami nawiasów otwierających / zamykających :)
DXM
@DXM: nie klawiatury, mają dodatkowe urządzenie wejściowe, które przypomina pedały fortepianowe do otwierania i zamykania nawiasów ;-)
vartec
@DXM, vartec: Ostatnio robiłem jakiś program i uważam, że nawiasy są OK. Niektóre kody C ++ mogą być znacznie bardziej tajemnicze (i mam znacznie większe doświadczenie z C ++ niż ze Scheme). :-)
Giorgio
9

Biorąc udział w najnowszej historii tutaj, uważam, że jednym z czynników było dodanie dodatków generycznych do Java i .NET. To oczywiście prowadzi do Func < , > i innych silnie wpisanych abstrakcji obliczeniowych (Zadanie < >, Async < > itp.)

W świecie .NET dodaliśmy te funkcje właśnie w celu obsługi FP. Wywołało to kaskadowy zestaw prac językowych związanych z programowaniem funkcjonalnym, zwłaszcza C # 3.0, LINQ, Rx i F #. Postęp ten wpłynął również na inne ekosystemy i nadal trwa do dziś w C #, F # i TypeScript.

Oczywiście pomaga również Haskellowi pracować w MSR :)

Oczywiście było też wiele innych wpływów (JS na pewno), a na te kroki wpłynęło wiele innych rzeczy - ale dodanie do tych języków generyków pomogło przełamać sztywną ortodoksję OO z późnych lat 90. w dużej części świata oprogramowania i pomogło otworzyć drzwi do FP.

Don Syme

ps F # był 2003, a nie 2005 - choć powiedzielibyśmy, że nie osiągnął 1.0 do 2005 roku. Zrobiliśmy również prototyp Haskell.NET w latach 2001-02.

Don Syme
źródło
Witamy! Użyłem 2005 dla F #, ponieważ jest to rok opisany w artykule na Wikipedii F # jako rok pierwszego stabilnego wydania. Czy chciałbym, żebym zmienił go na 2003 rok?
yannis,
4

To nie jest poważna odpowiedź, ale pytanie przypomniało mi fajny humorystyczny post Jamesa Iry'ego - Krótka, niekompletna i przeważnie zła historia języków programowania, która zawiera następujące zdanie:

„Lambdy są relegowane do względnego zaciemnienia, dopóki Java nie uczyni ich popularnymi przez ich brak”.

yoniLavi
źródło
złote zdanie :)
pistache
4

Z tego, co widzę, większość odpowiedzi koncentruje się na wyjaśnieniu, dlaczego programowanie funkcjonalne w ogóle powróciło i stało się głównym nurtem. Czułem, że to jednak tak naprawdę nie odpowiada na pytanie o anonimowe funkcje i dlaczego nagle stały się tak popularne.

To, co naprawdę zyskało na popularności, to zamknięcia . Ponieważ w większości przypadków zamknięciami są funkcje odrzucania przekazywane zmienne, oczywiście ma sens zastosowanie do nich anonimowej składni funkcji. W rzeczywistości w niektórych językach jest to jedyny sposób na zamknięcie.

Dlaczego zamknięcia zyskały popularność? Ponieważ są przydatne w programowaniu sterowanym zdarzeniami, podczas tworzenia funkcji zwrotnych . Obecnie jest to sposób pisania kodu klienta JavaScript (w rzeczywistości jest to sposób pisania dowolnego kodu GUI). Obecnie jest to również sposób pisania wysoce wydajnego kodu zaplecza, a także kodu systemowego, ponieważ kod zapisany w paradygmacie sterowanym zdarzeniami jest zwykle asynchroniczny i nieblokujący . W przypadku back-endu stało się to popularne jako rozwiązanie problemu C10K .

vartec
źródło
Dziękujemy za podkreślenie, że to pytanie nie dotyczy programowania funkcjonalnego (+1), ponieważ (1) idea bloku kodu przekazywanego jako argument jest również używana w językach niefunkcjonalnych, takich jak Smalltalk, i (2) stan mutacji przechwycone z kontekstu leksykalnego zamknięcia (jak to możliwe w wielu implementacjach lambda) jest zdecydowanie niefunkcjonalne . I tak, po zamknięciu, krok do anonimowych zamknięć jest krótki. Interesujące jest to, że zamknięcia były również znane od dawna, a programowanie oparte na zdarzeniach jest używane (o ile mi wiadomo) od lat osiemdziesiątych.
Giorgio
Ale może dopiero w ciągu ostatnich kilku lat stało się jasne, że zamknięcia można stosować znacznie częściej, niż wcześniej sądzono.
Giorgio
@Giorgio: tak, większość obecnie używanych koncepcji istnieje bardzo, bardzo długo. Jednak nie były używane w taki sposób, są teraz używane.
vartec
1

Myślę, że powodem jest rosnąca częstość programowania współbieżnego i rozproszonego, gdzie rdzeń programowania obiektowego (hermetyzowanie zmieniającego się stanu za pomocą obiektów) nie ma już zastosowania. W przypadku systemu rozproszonego, ponieważ nie ma żadnych dodanych państwowe (i programowe abstrakcje tej koncepcji są nieszczelne), aw przypadku systemu współbieżnego, bo właściwie synchronizowania dostęp do wspólnego państwa Udowodniono uciążliwe i podatne na błędy. Oznacza to, że jedna z kluczowych korzyści programowania obiektowego nie ma już zastosowania do wielu programów, co sprawia, że ​​paradygmat zorientowany obiektowo jest o wiele mniej pomocny niż kiedyś.

W przeciwieństwie do tego, paradygmat funkcjonalny nie wykorzystuje stanu zmiennego. Każde doświadczenie, które zdobyliśmy w zakresie funkcjonalnych paradygmatów i wzorców, jest zatem łatwiejsze do przeniesienia na obliczenia współbieżne i rozproszone. Zamiast na nowo wynaleźć koło, przemysł zapożycza teraz te wzory i funkcje językowe, aby zaspokoić swoje potrzeby.

meriton
źródło
4
Anonimowe funkcje w niektórych językach głównego strumienia (np. C ++ 11) pozwalają na stan zmienny (mogą nawet przechwytywać zmienne ze środowiska definiującego i zmieniać je podczas ich wykonywania). Myślę więc, że mówienie o ogólnym paradygmacie funkcjonalnym, a zwłaszcza o niezmienności, jest nieco poza zakresem zadawanego pytania.
Giorgio
Po zapoznaniu się z niektórymi uwagami na temat Java 8, jednym z głównych celów projektu lambda jest obsługa współbieżności. I to natychmiast zabiera nas do mutbombowej bomby kasetowej, na którą wpadną wszyscy ci cudowni javabeanie. Gdy Java otrzyma lambdas (zakładając, że tak naprawdę robi to w końcowej wersji wersji 8), muszą one w jakiś sposób rozwiązać problem niezmiennego domyślnego (w pewnym sensie niszczy język, myśląc w Lisp - funkcje wolne od efektów ubocznych - zamiast tego z w języku COBOL - walnięcie w DANE DIVISION / COPYBOOK)
Roboprog
Dobrze powiedziane. Odejście od stanu zmiennego ułatwia współbieżność, a technologie takie jak cascalog i spark łatwo rozpowszechniają funkcjonalne programowanie w klastrze komputerów. Zobacz glennengstrand.info/analytics/distribut/functional/..., aby uzyskać więcej informacji na temat tego, jak i dlaczego.
Glenn
1

Jeśli mogę dodać moje 0,02 €, chociaż zgadzam się ze znaczeniem JavaScript, który wprowadza tę koncepcję, myślę, że bardziej niż równoczesne programowanie obwiniłbym obecny sposób programowania asynchronicznego. Podczas wykonywania wywołań asynchronicznych (niezbędnych na stronach internetowych) proste anonimowe funkcje są tak oczywiście przydatne, że każdy programista WWW (tj. Każdy programista) musiał bardzo dobrze zapoznać się z tą koncepcją.

mcepl
źródło
1

Innym naprawdę starym przykładem czegoś podobnego do anonimowych funkcji / lambdas jest call-by-name w Algolu 60. Zauważ jednak, że call-by-name jest bliższy przekazywaniu makr jako parametrów niż przekazywaniu prawdziwych funkcji i jest bardziej kruchy / trudniejszy do rozumiem w rezultacie.

Stephen C.
źródło
0

Oto pochodzenie według mojej najlepszej wiedzy.

  • 2005: Javascript ostatnio wprowadził programowanie wyższego rzędu z lambdas z powrotem do głównego nurtu. W szczególności biblioteki takie jak underscore.js i jquery . Jedną z pierwszych tych bibliotek był prototype.js, który wyprzedza jquery o około rok. Prototyp oparty jest na module Enumerable Ruby, który prowadzi nas do…
  • 1996: Moduł Ruby Enumerable najwyraźniej czerpie inspirację z frameworku Smalltalk. Jak wspomniał Matz w wielu wywiadach, co prowadzi nas do…
  • 1980: Smalltalk używa dużo programowania wyższego rzędu i zapewnia kolekcjonerski interfejs API, który intensywnie wykorzystuje programowanie wyższego rzędu (np. Klasa Iterable GNU Smalltalk ). W idiomatycznym kodzie Smalltalk nie znajdziesz żadnego dla pętli, a jedynie wyliczenia o wysokim poziomie. Niestety, kiedy Java, kiedy struktura kolekcji Smalltalk została przeniesiona na Javę w 1998 roku, wyliczenia wyższego rzędu zostały pominięte. W ten sposób programowanie wyższego rzędu zostało wycofane z głównego nurtu na najbliższe dziesięć lat! Smalltalk ma wiele przodków, ale istotny dla pytania OP jest LISP, który prowadzi nas do…
  • 1958: LISP ma oczywiście programowanie wyższego rzędu.
akuhn
źródło
Amiss to oczywiście całe pochodzenie ML. ML, SML, OCaml, Haskell, F #. To musi się na coś liczyć ...
Muhammad Alkarouri,
-1

Funkcje anonimowe są fajne, ponieważ nazywanie rzeczy jest trudne, a jeśli używasz funkcji tylko w jednym miejscu, nie potrzebuje ona nazwy.

Funkcje lambda dopiero niedawno stały się głównym nurtem, ponieważ do niedawna większość języków nie obsługiwała zamknięć.

Sugerowałbym, że Javascript wprowadził ten główny nurt. Jest to uniwersalny język, w którym nie ma możliwości wyrażenia równoległości, a anonimowe funkcje ułatwiają korzystanie z modeli wywołań zwrotnych. Dodatkowo przyczyniły się popularne języki, takie jak Ruby i Haskell.

Matt Joiner
źródło
1
„Funkcje Lambda dopiero niedawno stały się głównym nurtem, ponieważ do niedawna większość języków nie obsługiwała zamknięć.”: To rozumowanie wydaje mi się nieco okrągłe: bycie głównym oznacza, że ​​większość języków je obsługuje. Można od razu zapytać „Co spowodowało popularność zamknięć we współczesnych językach programowania”.
Giorgio,
Wiem, że Python nie ma najlepszej implementacji lambd. Ale pod względem popularności prawdopodobnie przyczynił się więcej niż Haskell.
Muhammad Alkarouri,