Що це за «лямбда», про який всі говорять?


93

Що це за «лямбда», про який всі говорять? Дуже багато людей, схоже, люблять це, але все, що я можу зібрати з цього, це лише спосіб набити багато рядків коду в один вираз.

Може хтось, будь ласка, просвітить мене на її справжню цінність?


16
Чи можу я зазначити відповідачам, що запитуючий ніде не згадує .net

1
перевірити це пов'язаний Qn stackoverflow.com/questions/16501/what-is-a-lambda-function
yesraaj

Яке питання. Спасибі за запитання.
Арахіс

Лямбди належать до світу функціонального програмування (Декларативне програмування).
RBT

Відповіді:


179

Функції без імені

Простіше кажучи, лямбда - це функція без імені, або анонімна функція. Невеликий шматочок виконуваного коду, який можна передавати навколо, ніби він був змінною. У 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
});

Як бачите, використовуючи лямбдати, ми змогли абстрагувати логіку кешування / запам'ятовування. Якщо для іншого прикладу були певні вирішення, я вважаю, що ця проблема навряд чи вирішена за допомогою інших методик. Нам вдалося вилучити деякі важливі зразкові коди в одне місце. Не кажучи вже про те, що ми позбулися змінних usersand і photosglobal.

Переглядаючи ваш профіль, я бачу, що ви в основному користувач Python. Для вищевказаного зразка Python має концепцію декораторів. У мережі є безліч прикладів для декораторів мемоізації . Єдина відмінність полягає в тому, що в Python ви, швидше за все, маєте названу вкладену функцію всередині цієї функції декоратора. Причина в тому, що Python підтримує лише одновиражені лямбди. Але концепція однакова.

Як приклад використання лямбди Python. Наведений вище код, за яким ми відфільтрували парні числа, може бути представлений на Python так:

filter(lambda x: x % 2 == 0, [1, 2, 3, 4])

У будь-якому випадку, лямбди не такі потужні без закриття. Закриття - це те, що робить концепцію лямбдів настільки потужною. У своєму прикладі запам'ятовування я використав закриття, щоб створити закриття навколо storeпарами. Таким чином, у мене є доступ до цього парамуму навіть після того, як memoizeфункція повернула результат (лямбда).


3
Ого, ви витрачаєте на це багато часу.
mk12

4
@ Mk12, власне написавши відповідь, не дуже. Вивчаючи цей матеріал, так, минуло певний час, як я почав :)
Ionuț G. Stan

Хороша відповідь, але відсутня інформація про "функціональні інтерфейси" (з точки зору Java).
djangofan

Що це за оператори "===" у вашому "Абстрагуванні кодового коду"?
Дон


19

Термін "лямбда" використовується для позначення анонімної функції, зазвичай закриття . Вони корисні, оскільки дозволяють писати функції, які використовують інші функції, не роздуваючи код без необхідності. Наприклад, у Ruby:

(1..100).select {|num| num % 2 == 0}

Це створить масив, що містить парні числа від 1 до 100. Нам не потрібно виписувати явний цикл - метод select приймає функцію, яку він використовує для тестування значень, тому все, що нам потрібно, це наша власна логіка. Це дозволяє нам значно налаштувати метод, практично не докладаючи зусиль або накладних витрат. В основному, ми можемо складати функції з менших функцій.

Це лише простий приклад того, що вони можуть зробити. Можливість передавати функції як дані - це дійсно потужна і функціональна мова програмістів звичайно роблять з нею справді дивовижні речі.


6
Можливо, вам слід додати, що річ у трубах є параметром. Я один із цих людей, котрі мають проблеми з читанням рубіну.
Скурмедель

Це приємна відповідь. Єдина причина, чому Іонут отримав свій голос, полягає в тому, що він сказав нам, чому ми повинні дбати (детально) про лямбди.
Frank Shearar

Я б не погодився, що лямбди - це зазвичай закриття.
jwg

6

"Лямбда", можливо, занадто мало. Погляньте на Лямбда-числення . Це корисно у функціональному програмуванні.

А функціональне програмування - це ще одна парадигма програмування (на зразок процедурного чи об’єктно-орієнтованого).


5
Потім люди говорять про "лямбда", швидше за все, вони говорять про анонімну функцію, функціональні покажчики, закриття чи щось подібне. Майже ніколи не посилаються на справжнє лямбда-обчислення.
J-16 SDiZ

Радий, що ви згадали Лямбда-числення.! +1.
RBT

5

Лямбди в .NET досить часто називають "синтаксичним цукром". Вони безпосередньо не впливають на функціональність, однак полегшують користувачу мову.

Коли ви зрозуміли силу їх використання, я впевнений, ви побачите, що ви будете писати менше коду порівняно зі старим стилем із використанням делегатів / анонімних методів.


1
Я не думаю, що хтось згадав .NET, тому ОП, ймовірно, краще з більш загальною відповіддю.
molf

2
саме тому я уточнив, відповідаючи на те, що про .net. Якщо інші щебечуть із їхньою мовною реалізацією, тоді питання та відповіді допоможуть багатьом людям, незалежно від того, який вибір мови.
переосмислити

Ці відповіді звучать так, ніби ви щось чули про лямбди, але ви самі їх ще не розумієте.
jwg

2

Доктор Доббс Журнал має корисну статтю, що вводить лямбда-вирази (в контексті 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 є "Як правило, лямбда-вирази використовуються, коли потрібні невеликі і не надто складні функції на сайті виклику. Якби ця функція була нетривіальною, ви б не хотіли вирази лямбда, а нормальної функції або об'єкт функції ".


2

Якщо ви коли-небудь працювали з функціями / методами, які використовують вказівники функцій, делегати, стратегію чи обробку шаблону / події спостерігачів і думали про себе: "Я пишу всю цю функцію просто для того, щоб її використовувати лише один раз - щоб передати її цьому методу Я б хотів, щоб я міг просто записати його на місці, а не захаращувати свій код "- саме тут ви можете використовувати функції Lambda. Мови, що підтримують цю конструкцію, також зазвичай сильно користуються концепцією передачі функцій як параметрів, особливо стосовно роботи зі списками (функції першого класу та функції вищого порядку). Особливо це стосується функціональних мов, які для обчислень покладаються не на склад функції, а не на модифікацію пам'яті. У деяких випадках (такими мовами, як Python),


2

Слово "лямбда" - термінологія з тих часів, коли типи інформатики, швидше за все, навчалися з математики чи логіки, ніж отримали ступінь інформатики. Деякі з них готували парадигму під назвою «функціональне програмування», зовсім інша від імперативної і досить потужної. AFAIK - це середовище, де цей термін увійшов у вживання.

Математики та логіки вживають дивні слова.

"лямбда" звучить по-справжньому езотерично - ніби це дуже дивна і особлива річ. Дійсно, якщо ви пишете JavaScript для програми веб-браузера і використовуєте ідіому "var foo = function () {...}", ви весь час використовували лямбда-функції.


1

Лямбда-вираз - це проста форма функції. Ідея полягає в тому, що щось із форми зліва (еквівалентно параметрам) стає чимось формою праворуч (рівнозначним тілу).

наприклад, в c різкому:

x => x * x

- це лямбда на квадрат значення. Щось із форми

x

стає чимось формою

x * x

0

"Лямбда-вираз - це анонімна функція, яка може містити вирази та висловлювання та може використовуватися для створення делегатів або типів дерев виразів.

Усі лямбда-вирази використовують оператор лямбда =>, який читається як "переходить до". Ліва сторона лямбда-оператора визначає вхідні параметри (якщо такі є), а права - блок виразу або оператора. Лямбда-вираз x => x * x читається "x переходить до x разів x".

від MSDN


4
Так, Microsoft змушує всіх думати, що вони їх винайшли. Хоча лямбдаські вирази передують Microsoft. Це математичний термін, який застосовується до декількох мов програмування. (Що можливо, оскільки математика сама по собі може вважатися комп'ютерною мовою.)
Wim ten Brink

4
Зауважте, що це стосується впровадження .Net Microsoft. Це не величезне відхилення від загальної ідеї лямбда, але я думаю, що функціонал, реалізований у Lisp, є більш "стандартним".
Чак

2
Ця відповідь зовсім не пояснює, що таке лямбда (потребує визначення анонімної функції, делегата, типу дерева виразів) і, звичайно, не пояснює, яке її значення.
danio

0

Щоб отримати повне пояснення щодо лямбдаських виразів, також перегляньте Вікіпедію . (Прокрутіть униз до частини обчислення лямбда та мови програмування .) Вирази лямбда не такі вже й нові, вони не просто частина C #, а щось, що було введено в обчислення майже 80 років тому! Лямбда-вирази є основою для функціонального програмування.

Це цінність? Ну, враховуючи, що це насправді досить старе, я б сказав: дуже цінний для тих, хто робить розрахунки.


0

Якщо ви перебуваєте на Java, за останні пару місяців ви багато чули про лямбдаси та закриття, оскільки були різні пропозиції щодо додавання цієї функції до Java 7. Однак я думаю, що комітет її відмовив. Одна з пропозицій від Ніла Гафтера і дуже докладно пояснена тут: javac.info . Це допомогло мені зрозуміти випадки використання та переваги (особливо перед внутрішніми класами)




-1

Так, це лише спосіб натягування безлічі рядків коду в один вираз. Але, будучи таким ефективним набором кадрів, це дає можливість отримати нові способи структурування вашої програми.

Часто можна уникнути написання делегатів або зворотних викликів і повернутися до процедурного стилю просто тому, що занадто багато роботи для оголошення нових функцій або класів для одного виразу.

Ламбда-вирази дозволяють використовувати зворотні дзвінки навіть для найдрібніших завдань, що може зробити код більш зрозумілим. Не може.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.