Что это за «лямбда», о которой все говорят? Кажется, многим это нравится, но все, что я могу извлечь из этого, - это просто способ втиснуть множество строк кода в одно выражение.
Может ли кто-нибудь объяснить мне его истинную ценность?
Что это за «лямбда», о которой все говорят? Кажется, многим это нравится, но все, что я могу извлечь из этого, - это просто способ втиснуть множество строк кода в одно выражение.
Может ли кто-нибудь объяснить мне его истинную ценность?
Ответы:
Проще говоря, лямбда - это функция без имени или анонимная функция. Небольшой фрагмент исполняемого кода, который можно передавать, как если бы это была переменная. В JavaScript:
function () {}; // very simple
Давайте теперь посмотрим, как использовать эти лямбды.
Лямбды можно использовать для абстрагирования шаблонного кода. Например петли. Мы привыкли писатьfor
и while
зацикливаться целый день. Но это код, который не пишется. Мы могли бы извлечь код внутри цикла, наиболее важной части цикла, и абстрагироваться от остального:
for (var i=0; i<array.length; i++) {
// do what something useful with array[i]
}
используя forEach
объектов массива становится:
array.forEach(function (element, index) {
// do something useful with element
// element is the equivalent of array[i] from above
});
Вышеупомянутая абстракция может быть не такой полезной, но есть и другие функции более высокого порядка, например forEach
, которые выполняют гораздо более полезные задачи. Например filter
:
var numbers = [1, 2, 3, 4];
var even = [];
// keep all even numbers from above array
for (var i=0; i<numbers.length; i++) {
if (numbers[i] % 2 === 0) {
even.push(numbers[i]);
}
}
alert(even);
// Using the filter method
even = [1, 2, 3, 4].filter(function (number) {
return number % 2 === 0;
});
alert(even);
В некоторых средах, в которых доступна концепция события, мы могли бы использовать лямбда-выражения для ответа на события, которые могут произойти в определенный момент времени.
window.onload = function () {
alert("Loaded");
};
window.setTimeout(function () {
alert("Code executed after 2 seconds.");
}, 2000);
Это можно было сделать и другими способами, но они довольно многословны. Например, в Java естьRunnable
интерфейс.
До этого момента мы использовали лямбда-выражения в основном из-за его синтаксических возможностей сахара. Но бывают ситуации, когда лямбды могут быть намного полезнее. Например, у нас могут быть функции, возвращающие лямбды. Допустим, у нас есть функция, возвращаемые значения которой должны быть кэшированы.
var users = [];
var getUser = function (name) {
if (! users[name]) {
// expensive operations to get a user. Ajax for example
users[name] = user_from_ajax;
}
return users[name];
};
Позже мы можем заметить, что у нас есть похожая функция:
var photos = [];
var getPhoto = function (name) {
if (! photo[name]) {
// expensive operations to get a user. Ajax for example
photos[name] = photo_from_ajax;
}
return photos[name];
};
Здесь явно есть шаблон, поэтому давайте абстрагируемся от него. Воспользуемся мемоизацией .
/**
* @param {Array} store Data structure in which we cache lambda's return values
* @param {Function} lambda
* @return {Function} A function that caches the result of calling the lambda param
*/
var memoize = function (store, lambda) {
// return a new lambda
return function (name) {
if (! store[name]) {
// Execute the lambda and cache the result
store[name] = lambda(name);
}
return store[name];
};
};
var getUsers = memoize([], function (name) {
// expensive operations to get a user. Ajax for example
});
var getPhotos = memoize([], function (name) {
// expensive operations to get a photo. Ajax for example
});
Как видите, с помощью лямбда-выражений мы смогли абстрагироваться от логики кеширования / запоминания. Если бы для другого примера были какие-то обходные пути, я считаю, что эту конкретную проблему вряд ли можно решить с помощью других методов. Нам удалось собрать важный шаблонный код в одном месте. Не говоря уже о том, что мы избавились отusers
и photos
глобальных переменных.
Глядя на ваш профиль, я вижу, что вы в основном пользователь Python. Для вышеприведенного шаблона в Python есть концепция декораторов. В сети есть множество примеров для декораторов мемоизации . Единственная разница в том, что в Python у вас, скорее всего, есть именованный вложенная функция внутри этой функции-декоратора. Причина в том, что Python поддерживает только лямбды с одним выражением. Но концепция та же.
В качестве примера использования лямбда-выражения Python. Приведенный выше код, в котором мы отфильтровали четные числа, может быть представлен в Python следующим образом:
filter(lambda x: x % 2 == 0, [1, 2, 3, 4])
В любом случае, лямбды не так эффективны без замыканий. Замыкания - вот что делает концепцию лямбда настолько сильной. В моем примере с мемоизацией я использовал замыкания, чтобы создать замыкание вокруг store
параметра. Таким образом, у меня есть доступ к этому параметру даже после того, как memoize
функция вернула свой результат (лямбда).
Термин «лямбда» используется для обозначения анонимной функции, обычно замыкания . Они полезны, потому что позволяют писать функции, использующие другие функции, без ненужного раздувания кода. Например, в Ruby:
(1..100).select {|num| num % 2 == 0}
Это создаст массив, содержащий четные числа от 1 до 100. Нам не нужно писать явный цикл - метод select принимает функцию, которую он использует для проверки значений, поэтому все, что нам нужно, это наша настраиваемая логика. Это позволяет нам значительно настроить метод практически без усилий и накладных расходов. По сути, мы можем составлять функции из более мелких функций.
Это простой пример того, что они могут сделать. Возможность передавать функции в виде данных - это действительно мощный инструмент, и программисты на функциональных языках обычно делают с ними действительно удивительные вещи.
«Лямбда» может быть слишком мало. Взгляните на лямбда-исчисление . Это полезно в функциональном программировании.
А функциональное программирование - это еще одна парадигма программирования (например, процедурная или объектно-ориентированная).
Лямбды в .NET довольно часто называют «синтаксическим сахаром». Они не влияют напрямую на функциональность, но упрощают использование языка людьми.
Когда вы поймете силу их использования, я уверен, вы обнаружите, что будете писать меньше кода по сравнению со старым способом с использованием делегатов / анонимных методов.
В Dr Dobbs Journal есть полезная статья о лямбда-выражениях. (в контексте C ++, но я думаю, что вы можете применить эти принципы к любому языку).
Как говорится в статье: «Лямбда-выражение - это очень компактное выражение, которое не требует отдельного определения класса / функции».
Поэтому, используя примеры листингов 1 и 2 из DDJ вместо записи:
std::for_each( vec.begin(), vec.end(), print_to_stream<std::string>(std::cout));
Для этого требуется отдельное определение класса, например:
template <typename T, typename Stream> class print_to_stream_t {
Stream& stream_;
public:
print_to_stream_t(Stream& s):stream_(s) {}
void operator()(const T& t) const {
stream_ << t;
}
};
template <typename T,typename Stream>
print_to_stream_t<T,Stream> print_to_stream(Stream& s) {
return print_to_stream_t<T,Stream>(s);
}
Используя лямбда-библиотеку Boost, это может стать:
std::for_each(vec.begin(),vec.end(),std::cout << _1);
Что сохраняет определение встроенным.
В статье также объясняются некоторые другие применения лямбда-выражений.
Я думаю, что ключевой момент в статье DDJ : «Обычно лямбда-выражения используются, когда на месте вызова требуются небольшие и не слишком сложные функции. Если бы функция была нетривиальной, вам бы не понадобилось лямбда-выражение, а обычная функция или функциональный объект ".
Если вы когда-либо работали с функциями / методами, которые используют указатели на функции, делегаты, стратегию или шаблон наблюдателя / обработку событий, и думали про себя: «Я пишу всю эту функцию, чтобы использовать ее только один раз - чтобы передать ее этому методу. ; Хотел бы я просто написать это на месте, а не загромождать свой код »- вот где вы можете использовать лямбда-функции. Языки, поддерживающие эту конструкцию, также обычно в значительной степени используют преимущества концепции передачи функций в качестве параметров, особенно в отношении работы со списками (функции первого класса и функции более высокого порядка). Это особенно верно для функциональных языков, которые для вычислений полагаются на композицию функций, а не на изменение памяти. В некоторых случаях (в таких языках, как Python),
«лямбда» как слово - это терминология тех времен, когда люди, занимающиеся информатикой, могли обучаться математике или логике с большей вероятностью, чем иметь степень в области компьютерных наук. Некоторые из них придумали парадигму под названием «функциональное программирование», весьма отличную от императивного и весьма мощную. Насколько мне известно , это среда, в которой термин вошел в употребление.
Математики и логики склонны использовать странные слова.
«лямбда» звучит действительно эзотерически - как будто это очень странная и особенная вещь. На самом деле, если вы пишете JavaScript для приложения веб-браузера и используете идиому «var foo = function () {...}», вы всегда использовали лямбда-функции.
Лямбда-выражение - это простая форма функции. Идея состоит в том, что что-то от формы слева (эквивалентное параметрам) становится чем-то вроде формы справа (эквивалентным телу).
например, до-диез:
x => x * x
лямбда для вычисления квадрата значения. Что-то в форме
x
становится чем-то вроде
x * x
«Лямбда-выражение - это анонимная функция, которая может содержать выражения и инструкции, и может использоваться для создания делегатов или типов дерева выражений.
Во всех лямбда-выражениях используется лямбда-оператор =>, который читается как «переходит к». Левая часть лямбда-оператора определяет входные параметры (если есть), а правая часть содержит блок выражения или оператора. Лямбда-выражение x => x * x читается как «x переходит в x, умноженное на x».
из MSDN
Полное объяснение лямбда-выражений можно найти в Википедии . (Прокрутите вниз до раздела « Лямбда-исчисление и языки программирования» .) Лямбда-выражения не новы, и они не просто часть C #, а то, что было введено в вычисления почти 80 лет назад! Лямбда-выражения являются основой функционального программирования.
Это ценность? Что ж, учитывая, что он на самом деле довольно старый, я бы сказал: очень ценный для любого, кто делает вычисления.
Если вы занимаетесь Java, вы много слышали о лямбдах или замыканиях за последние пару месяцев, потому что были разные предложения по добавлению этой функции в Java 7. однако, я думаю, что участник отказался от нее. Одно из предложений сделано Нилом Гафтером и подробно описано здесь: javac.info . Это помогло мне понять варианты использования и преимущества (особенно по сравнению с внутренними классами).
Вы найдете все, что вам нужно знать (о C # Lambdas) для начала здесь:
Lambda-выражения
Для java-лямбд это может быть хорошей отправной точкой:
http://rodrigouchoa.wordpress.com/2014/09/10/java-8-lambda-expressions-tutorial/
Да, это просто способ втиснуть множество строк кода в одно выражение. Но, будучи настолько эффективным, он позволяет по-новому структурировать вашу программу.
Часто можно избежать написания делегатов или обратных вызовов и вернуться к процедурному стилю просто потому, что объявлять новые функции или классы для одного выражения слишком много.
Лямбда-выражения делают целесообразным использование обратных вызовов даже для самых крошечных задач, что может сделать код более понятным. Может не.