Jaka jest różnica między funkcją a lambda?

54

Jestem trochę zdezorientowany co do „funkcji” i „lambda”. Widziałem kilka przykładów pokazujących, że słowo kluczowe schematu lambdadziała bardzo podobnie do słowa kluczowego JavaScript function, ale tak naprawdę nie wiem, jak są ze sobą powiązane.

Powiedziano mi, że „funkcji” i „metody” można używać zamiennie, mówiąc o obiektach w .net. Zastanawiam się, czy „lambda” i „funkcja” podobnie oznaczają to samo. Zastanawiam się, czy „lambda” ma jakieś ezoteryczne znaczenie, biorąc pod uwagę, że grecka litera lambda (λ) pojawia się w tylu awatarach na tej stronie. Aby jeszcze bardziej skomplikować sprawę, w .net funkcjonalne części języka C # odnoszą się do wyrażeń funkcyjnych przekazywanych do innej funkcji jako „wyrażeń lambda”, więc to słowo wydaje się być wszędzie.

Nieokreślony jestem również termin „rachunek lambda”.

Jaka jest różnica między funkcją a lambda?

Ciastka Z Mąki Ryżowej
źródło
3
Nitpick - nazywane są „wyrażeniami lambda”, a nie „funkcjami lambda”, przynajmniej w zakresie dokumentacji C # / .NET.
Oded
@ TWith2Sugars - Przeczytaj wiadomość. Twoja odpowiedź jest niskiej jakości, ponieważ jest to po prostu link, więc został przekształcony w komentarz.
Oded
17
I wonder if 'lambda' has some esoteric meaning, seeing that the Greek letter lambda (λ) appears in so many avatars on this site.Można by mieć nadzieję, że byłoby to w odniesieniu do rachunku lambda, ale mam dziwne przeczucie, że Half Life jest winny awatarom lambda.
yannis
3
W
porządku
@ZaphodBeeblebrox: Podejrzewam, że masz rację co do wpływu Half-Life. : /
FrustratedWithFormsDesigner

Odpowiedzi:

44

Słowo „lambda” lub „wyrażenia lambda” najczęściej odnosi się do funkcji anonimowych. W tym sensie lambda jest rodzajem funkcji, ale nie każda funkcja jest lambda (tzn. Nazwane funkcje zwykle nie są nazywane lambdami). W zależności od języka funkcje anonimowe są często implementowane inaczej niż funkcje nazwane (szczególnie w językach, w których funkcje anonimowe są zamknięciami, a funkcje nazwane nie są), więc odwołanie się do nich za pomocą innych terminów może mieć sens.

Różnica między słowem kluczowym lambda schematu a słowem kluczowym funkcji Javascript polega na tym, że tego ostatniego można używać zarówno do tworzenia anonimowych funkcji, jak i nazwanych funkcji, podczas gdy ten pierwszy tworzy tylko funkcje anonimowe (i można by użyć definedo tworzenia nazwanych funkcji).

Rachunek lambda jest minimalnym językiem programowania / modelem matematycznym obliczeń, który wykorzystuje funkcje jako jedyną „strukturę danych”. W rachunku lamdba symbol lambda służy do tworzenia (anonimowych) funkcji. Stąd bierze się użycie terminu „lambda” w innych językach.

sepp2k
źródło
1
To jest bardzo szorstkie. Do tworzenia nazw używasz define(lub letjednego z jego krewnych albo definicji wewnętrznej) - to wszystko. Nie ma nic specjalnego w defineodniesieniu do funkcji.
Eli Barzilay,
2
@EliBarzilay Cóż, define nie ma specjalnego formularza definiowania funkcji (czyli można napisać (define (f x) (foo))zamiast (define f (lambda (x) (foo)))), ale chodzi mi o to, że nie można stworzyć za pomocą funkcji o nazwie lambdasam, czyli nie można napisać coś jak (lambda f (x) (foo))zdefiniować funkcję o nazwie fktóry wymaga jednego argumentu, tak jak w przypadku functionsłowa kluczowego Javascript .
sepp2k
1
definema to jako cukier składniowy, więc nie jest tak ważne, jak jego rola jako narzędzia wiążącego nazwy dla wszystkich wartości. Co do tego, że lambdanie tworzy nazwy sam w sobie: to ważna cecha, ponieważ oddziela ona dawanie nazwy od formularzy funkcyjnych ... IMO JS robi dobrze, pozwalając na separację, jednocześnie akceptując opcjonalną nazwę dla tych mas, które byłyby przerażone pomysł na funkcję bez nazwy. (I na szczęście wielkość tych mas ogólnie spada ...)
Eli Barzilay
18

Lambda jest po prostu funkcją anonimową - funkcją bez nazwy.

Oded
źródło
4
Uwaga Całkiem: lambda mogą zawierać stan (jak w zamknięciu), że zaczepiają się w kontekście, w którym zostały zadeklarowane.
Martin York,
7
Podobnie może być nazwana funkcja, jeśli język pozwala zadeklarować funkcje zagnieżdżone.
cHao
4
Wyrazy uznania za przejście do zakładki „posty niskiej jakości” z pozytywną odpowiedzią.
yannis
@ZaphodBeeblebrox - Nie celowo, zapewniam cię.
Oded
Nie do końca, lambdawyrażenie w Schemacie jest jak functionwyrażenie bez imienia - ale nic nie stoi na przeszkodzie, aby później nadać im nazwę. Na przykład var f = [function(x){return x;}][0]. Można argumentować, że sama wartość funkcji nie ma nazwy, ale byłoby to prawdą dla wszystkich funkcji ...
Eli Barzilay,
8

W C # funkcja anonimowa to ogólny termin, który obejmuje zarówno wyrażenia lambda, jak i metody anonimowe (metody anonimowe są instancjami delegowanymi bez faktycznej deklaracji metody).

Wyrażenia lambda można podzielić na wyrażenie lambda i wyrażenie lambda

Wyrażenie lambda:

(int x, string y) => x == y.Length 

Instrukcja lambda jest podobna do wyrażenia lambda, z tą różnicą, że instrukcje są ujęte w nawiasy klamrowe:

(int x, string y) => {
         if (x == y.Length) {
             Console.WriteLine(y);
         }
}

Kiedy mówimy o wyrażeniach lambda w JavaScript, oznacza to po prostu użycie funkcji jako argumentu w wywołaniu innej funkcji.

var calculate = function(x, y, operation){
    return operation(x, y);
}

// we're passing anonymous function as a third argument
calculate(10, 15, function(x, y) {
    return x + y;
}); // 25
Christian P.
źródło
+1 Wiele osób wspomniało, że lambdy są funkcjami anonimowymi, ale jest w tym coś więcej. Ciało (prawa strona) lambda jest często wyrażeniem, a nie blokiem instrukcji. Ciało nazwanej funkcji będącej wyrażeniem jest zwykle dozwolone (lub wymagane) w językach funkcjonalnych, ale nie w językach imperatywnych.
Zantier
4

TL; DR Jak zauważyli inni: notacja lambda to tylko sposób na zdefiniowanie funkcji bez konieczności nadawania im nazwy.

Długa wersja

Chciałbym trochę rozwinąć ten temat, ponieważ uważam go za bardzo interesujący. Zastrzeżenie: Dawno temu podjąłem kurs na rachunku lambda. Jeśli ktoś z lepszą wiedzą znajdzie jakieś nieścisłości w mojej odpowiedzi, nie krępuj się, pomóż mi ją poprawić.

Zacznijmy wyrażeń, np 1 + 2i x + 2. Literały takie jak 1i 2są nazywane stałymi, ponieważ są powiązane z określonymi stałymi wartościami.

Identyfikator taki jak xnazywany jest zmienną. Aby go ocenić, najpierw musisz powiązać go z pewną wartością. Zasadniczo nie możesz oceniać, x + 1dopóki nie wiesz, co xjest.

Notacja lambda zapewnia schemat wiązania określonych wartości wejściowych ze zmiennymi. Ekspresji lambda może być utworzony przez dodanie λx .przed istniejącym ekspresji, np λx . x + 1. Zmienna xjest uważane za darmo w x + 1i związany wλx . x + 1

W jaki sposób pomaga to w ocenie wyrażeń? Jeśli podasz wartość do wyrażenia lambda, to tak

(λx . x + 1) 2

następnie możesz ocenić całe wyrażenie, zastępując (wiążąc) wszystkie wystąpienia zmiennej xwartością 2:

(λx . x + 1) 2
      2 + 1
      3

Tak więc notacja lambda zapewnia ogólny mechanizm wiązania rzeczy ze zmiennymi pojawiającymi się w bloku wyrażenia / programu. W zależności od kontekstu tworzy to wyraźnie różne pojęcia w językach programowania:

  • W czysto funkcjonalnym języku, takim jak Haskell, wyrażenia lambda reprezentują funkcje w sensie matematycznym: wartość wejściowa jest wstrzykiwana do ciała lambda i tworzona jest wartość wyjściowa.
  • W wielu językach (np. JavaScript, Python, schemat) ocena treści wyrażenia lambda może mieć skutki uboczne. W tym przypadku można użyć terminu procedura, aby zaznaczyć różnicę względem funkcji czystych.

Oprócz różnic notacja lambda polega na zdefiniowaniu parametrów formalnych i powiązaniu ich z parametrami rzeczywistymi.

Następnym krokiem jest nadanie funkcji / procedurze nazwy. W kilku językach funkcje są jak wszystkie inne, więc możesz nadać funkcji następującą nazwę:

(define f (lambda (x) (+ x 1)))      ;; Scheme

f = \x -> x + 1                      -- Haskell

val f: (Int => Int) = x => x + 1     // Scala

var f = function(x) { return x + 1 } // JavaScript

f = lambda x: x + 1                  # Python

Jak zauważył Eli Barzilay, te definicje po prostu wiążą nazwę fz wartością, która okazuje się funkcją. W związku z tym funkcje, liczby, ciągi znaków, wszystkie wartości, które można przypisać do nazw w ten sam sposób:

(define n 42)   ;; Scheme

n = 42          -- Haskell

val n: Int = 42 // Scala

var n = 42      // JavaScript

n = 42          # Python

W tych językach można również powiązać funkcję z nazwą, używając bardziej znanej (ale równoważnej) notacji:

(define (f x) (+ x 1))         ;; Scheme

f x = x + 1                    -- Haskell

def f(x: Int): Int = x + 1     // Scala

function f(x) { return x + 1 } // JavaScript

def f(x): return x + 1         # Python

Niektóre języki, np. C, obsługują tylko ten ostatni zapis do definiowania (nazwanych) funkcji.

Domknięcia

Kilka uwag końcowych dotyczących zamknięć . Rozważ wyrażenie x + y. Zawiera dwie wolne zmienne. Jeśli połączysz się xza pomocą notacji lambda, otrzymasz:

\x -> x + y

To nie jest (jeszcze) funkcja, ponieważ nadal zawiera wolną zmienną y. Możesz zrobić z niego funkcję, wiążąc yrównież:

\x -> \y -> x + y

lub

\x y -> x + y

który jest taki sam jak +funkcja.

Ale możesz powiązać, powiedzmy, yw inny sposób (*):

incrementBy y = \x -> x + y

Wynikiem zastosowania funkcji incrementBy do liczby jest zamknięcie, tj. Funkcja / procedura, której treść zawiera dowolną zmienną (np. y), Która została powiązana z wartością ze środowiska, w którym zdefiniowano zamknięcie.

Podobnie incrementBy 5jest z funkcją (zamknięcie), która zwiększa liczby o 5.

UWAGA (*)

Trochę tu oszukuję:

incrementBy y = \x -> x + y

jest równa

incrementBy = \y -> \x -> x + y

więc mechanizm wiązania jest taki sam. Intuicyjnie myślę, że zamknięcie reprezentuje fragment bardziej złożonego wyrażenia lambda. Po utworzeniu tej reprezentacji niektóre wiązania wyrażenia macierzystego zostały już ustawione, a zamknięcie używa ich później, gdy zostanie ocenione / wywołane.

Giorgio
źródło
Jestem tylko początkującym, ale myślę, że może to być nieco mylące, jeśli próbujesz zrozumieć rachunek λ w sensie matematycznym, ponieważ to, co nazywamy stałymi, jest nazywane zmiennymi i oznaczane symbolami a, b, c ... zmienne wywołania byłyby zmienną nieokreśloną x . Z drugiej strony 1 oznacza λ f x . f x , 2 oznacza λ f x . f ( f x ) i tak dalej.
jinawee
@jinawee: Przyznaję, że nie szukałem dokładnej definicji. Pamiętam, że w logice używam terminów zmienne i stałe. Tam stała jest symbolem, który jest odwzorowany na domenę, podczas gdy zmienna jest symbolem, nad którym można kwantyfikować. Ale znowu (1) minęło wiele lat, odkąd wziąłem kurs logiki, i (2) rachunek lambda nie musi przestrzegać 1-1 pojęć logiki matematycznej. Jeśli wskażesz mi odniesienie, mogę spróbować naprawić moją terminologię.
Giorgio
0

„Lambda” w programowaniu zwykle oznacza „funkcję lambda” (lub także „wyrażenie lambda”, „termin lambda”). Gdy funkcja jest nazwanym blokiem kodu zdefiniowanym przed użyciem, „funkcja lambda” to blok kodu (lub wyrażenie) zdefiniowany zamiast użycia, który może być używany jako obywatel pierwszej klasy w języku programowania.

W JavaScript ES6 (2015) istnieje krótka składnia definiująca lambdy o nazwie „Funkcje strzałek” . W języku C # taka składnia została wprowadzona w .NET 3.0 (około 2006) .

W matematyce pojęcie „funkcja” ma kilka znaczeń, w których jedno z nich dotyczy notacji funkcji (tj. Jak ją zapisać), a następnie „funkcja lambda” (w rachunku różniczkowym) jest szczególnym rodzajem notacji funkcji. Aby uzyskać więcej dyskusji, sprawdź funkcje lambda w językach programowania .

battlmonstr
źródło