Funkcje bez nazwy
Mówiąc najprościej, lambda to funkcja bez nazwy lub funkcja anonimowa. Mały fragment kodu wykonywalnego, który można przekazać tak, jakby był zmienną. W JavaScript:
function () {};
Zobaczmy teraz niektóre zastosowania tych lambd.
Abstrakcyjny kod schematyczny
Lambdy mogą być użyte do wyodrębnienia kodu standardowego. Na przykład pętle. Jesteśmy przyzwyczajeni do pisania for
i while
pętli przez cały dzień. Ale to jest kod, którego się nie pisze. Moglibyśmy wyodrębnić kod wewnątrz pętli, najważniejszą część pętli i usunąć resztę:
for (var i=0; i<array.length; i++) {
}
używając forEach
obiektów tablicy of, staje się:
array.forEach(function (element, index) {
});
Powyższa abstrakcja może nie być przydatna, ale istnieją inne funkcje wyższego rzędu, takie jak forEach
, które wykonują znacznie bardziej przydatne zadania. Na przykład filter
:
var numbers = [1, 2, 3, 4];
var even = [];
for (var i=0; i<numbers.length; i++) {
if (numbers[i] % 2 === 0) {
even.push(numbers[i]);
}
}
alert(even);
even = [1, 2, 3, 4].filter(function (number) {
return number % 2 === 0;
});
alert(even);
Opóźnienie wykonania kodu
W niektórych środowiskach, w których pojęcie zdarzenia jest dostępne, moglibyśmy użyć lambd, aby odpowiedzieć na zdarzenia, które mogą się wydarzyć w pewnym momencie.
window.onload = function () {
alert("Loaded");
};
window.setTimeout(function () {
alert("Code executed after 2 seconds.");
}, 2000);
Można to zrobić na inne sposoby, ale są one raczej rozwlekłe. Na przykład w Javie jest Runnable
interfejs.
Fabryki funkcji
Do tego momentu używaliśmy tylko lambd głównie ze względu na ich możliwości związane z cukrem syntaktycznym. Ale są sytuacje, w których lambdy mogą być znacznie bardziej przydatne. Na przykład możemy mieć funkcje, które zwracają lambdy. Powiedzmy, że mamy funkcję, dla której chcemy, aby jej zwracane wartości były buforowane.
var users = [];
var getUser = function (name) {
if (! users[name]) {
users[name] = user_from_ajax;
}
return users[name];
};
Później możemy zauważyć, że mamy podobną funkcję:
var photos = [];
var getPhoto = function (name) {
if (! photo[name]) {
photos[name] = photo_from_ajax;
}
return photos[name];
};
Jest tam wyraźnie jakiś wzór, więc odejmijmy go. Użyjmy zapamiętywania .
var memoize = function (store, lambda) {
return function (name) {
if (! store[name]) {
store[name] = lambda(name);
}
return store[name];
};
};
var getUsers = memoize([], function (name) {
});
var getPhotos = memoize([], function (name) {
});
Jak widać, używając lambd, byliśmy w stanie wyodrębnić logikę buforowania / zapamiętywania. Gdyby w drugim przykładzie istniały jakieś obejścia, uważam, że ten konkretny problem jest trudny do rozwiązania za pomocą innych technik. Udało nam się wyodrębnić ważny kod standardowy w jednym miejscu. Nie wspominając o tym, że pozbyliśmy się zmiennych globalnych users
i photos
.
Patrząc na Twój profil, widzę, że jesteś głównie użytkownikiem Pythona. W przypadku powyższego wzorca Python ma koncepcję dekoratorów. W sieci jest wiele przykładów dekoratorów zapamiętywania . Jedyną różnicą jest to, że w Pythonie najprawdopodobniej masz nazwaną zagnieżdżoną funkcję wewnątrz tej funkcji dekoratora. Powodem jest to, że Python obsługuje tylko wyrażenia lambda z jednym wyrażeniem. Ale koncepcja jest taka sama.
Jako przykład użycia lambda w Pythonie. Powyższy kod, w którym odfiltrowaliśmy liczby parzyste, można przedstawić w Pythonie w następujący sposób:
filter(lambda x: x % 2 == 0, [1, 2, 3, 4])
W każdym razie lambdy nie są tak potężne bez zamknięć. Zamknięcia są tym, co sprawia, że koncepcja lambd jest tak potężna. W moim przykładzie zapamiętywania użyłem domknięć, aby utworzyć zamknięcie wokół store
parametru. W ten sposób mam dostęp do tego parametru nawet po tym, jak memoize
funkcja zwróciła swój wynik (lambdę).