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.