В чем разница между функцией и лямбда?

54

Я немного запутался по поводу «функции» и «лямбды». Я видел несколько примеров, показывающих, что ключевое слово схема lambdaработает очень похоже на ключевое слово JavaScript function, но я действительно не знаю, как они связаны.

Мне сказали, что «функция» и «метод» могут использоваться взаимозаменяемо, когда речь идет об объектах в .net. Мне интересно, означают ли «лямбда» и «функция» одно и то же. Интересно, имеет ли «лямбда» какое-то эзотерическое значение, видя, что греческая буква лямбда (λ) появляется во многих аватарах на этом сайте. Чтобы сделать вещи еще более запутанными, в .net функциональные части C # ссылаются на выражения функций, передаваемые другой функции как «лямбда-выражения», поэтому слово действительно кажется повсеместным.

Я также смутно знаком с термином «лямбда-исчисление».

В чем разница между функцией и лямбда?

Печенье из рисовой муки
источник
3
Nitpick - они называются «лямбда-выражениями», а не «лямбда-функциями», по крайней мере, в том, что касается документации на C # / .NET.
Одед
@ TWith2Sugars - Прочтите сообщение. Ваш ответ низкого качества, так как это просто ссылка, поэтому он был преобразован в комментарий.
Отредактировано
17
I wonder if 'lambda' has some esoteric meaning, seeing that the Greek letter lambda (λ) appears in so many avatars on this site.Можно было бы надеяться, что это будет связано с лямбда-исчислением, но у меня странное чувство, что Half Life виноват в лямбда-аватарах.
Яннис
3
Справедливо, вот ссылка на ответ stackoverflow
TWith2Sugars
@ZaphodBeeblebrox: Я подозреваю, что вы правы относительно влияния Half-Life. : /
FrustratedWithFormsDesigner

Ответы:

44

Слово «лямбда» или «лямбда-выражения» чаще всего относится к анонимным функциям. Таким образом, в этом смысле лямбда является своего рода функцией, но не каждая функция является лямбда (то есть именованные функции обычно не называют лямбда-выражениями). В зависимости от языка анонимные функции часто реализуются иначе, чем именованные функции (особенно в языках, где анонимные функции являются замыканиями, а именованные функции - нет), поэтому обращение к ним с использованием различных терминов может иметь смысл.

Различие между ключевым словом lambda схемы и ключевым словом функции Javascript заключается в том, что последнее можно использовать для создания как анонимных функций, так и именованных функций, тогда как первое создает только анонимные функции (и вы будете использовать defineдля создания именованных функций).

Лямбда-исчисление - это минимальный язык программирования / математическая модель вычислений, которая использует функции в качестве единственной «структуры данных». В исчислении lamdba лямбда-символ используется для создания (анонимных) функций. Отсюда и использование термина «лямбда» в других языках.

sepp2k
источник
1
Это очень грубо. Вы используете define(или letодин из его родственников, или внутреннее определение) для создания имен - вот и все. Там нет ничего особенного в defineотношении функций.
Эли Барзилай
2
@EliBarzilay Ну, define действительно имеют специальную форму для определения функций (например , вы можете написать (define (f x) (foo))вместо (define f (lambda (x) (foo)))), но моя точка зрения в том , что вы не можете создать именованный функцию , используя lambdaодин, то вы не можете написать что - то вроде (lambda f (x) (foo))определить функцию с именем fэто принимает один аргумент, как вы можете с functionключевым словом Javascript .
sepp2k
1
defineимеет это как синтаксический сахар, так что это не так важно, как его роль инструмента привязки имени для всех значений. Что касается lambdaне создания имени само по себе: это важная особенность, поскольку она отделяет присвоение имен от форм функций ... IMO JS делает правильную вещь, разрешая разделение, одновременно принимая необязательное имя для тех масс, которые были бы в ужасе от идея функции без имени. (И, к счастью, размер этих масс в целом уменьшается ...)
Эли Барзилай
18

Лямбда - это просто анонимная функция - функция без имени.

Одед
источник
4
Примечание. Лямбда может содержать состояние (как в замыкании), что они попадают в контекст, в котором они объявлены.
Мартин Йорк,
7
То же самое можно сказать и с именованной функцией, если язык позволяет вам объявлять вложенные функции.
Цао
4
Престижность для того, чтобы сделать это во вкладке обзора "сообщений низкого качества" с поднятым голосом.
Яннис
@ZaphodBeeblebrox - Не намеренно, я могу вас заверить.
Отредактировано
Не совсем, lambdaвыражение в Scheme похоже на functionвыражение без имени, но ничто не мешает вам позже дать ему имя. Например var f = [function(x){return x;}][0]. Можно утверждать, что само значение функции не имеет имени, но это было бы верно для всех функций ...
Eli Barzilay
8

В C # анонимная функция - это общий термин, который включает как лямбда-выражения, так и анонимные методы (анонимные методы - это экземпляры делегатов без фактического объявления метода).

Лямбда-выражения можно разбить на выражение лямбда и выражение лямбда

Выражение лямбда:

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

Оператор лямбда аналогичен выражению лямбда, за исключением того, что оператор (ы) заключены в фигурные скобки:

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

Когда мы говорим о лямбда-выражениях в JavaScript, это просто означает использование функции в качестве аргумента при вызове другой функции.

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
Кристиан П
источник
+1 Многие люди упоминали, что лямбды - это анонимные функции, но это еще не все. Тело (правая часть) лямбды часто является выражением, а не блоком операторов. Тело именованной функции, являющейся выражением, обычно разрешено (или требуется) в функциональных языках, но не в императивных языках.
Зантье
4

TL; DR Как указывали другие: лямбда-нотация - это просто способ определения функций без необходимости давать им имя.

Длинная версия

Я хотел бы подробнее остановиться на этой теме, потому что я нахожу это очень интересным. Отказ от ответственности: я взял курс на лямбда-исчисление давным-давно. Если кто-то с более глубокими знаниями обнаружит какие-либо неточности в моем ответе, не стесняйтесь помочь мне улучшить его.

Давайте начнем с выражений, например, 1 + 2и x + 2. Такие литералы, как 1и 2, называются константами, поскольку они связаны с конкретными фиксированными значениями.

Такой идентификатор xназывается переменным, и для его оценки вам необходимо сначала привязать его к некоторому значению. Таким образом, в основном вы не можете оценить, x + 1пока вы не знаете, что xесть.

Лямбда-нотация обеспечивает схему для привязки определенных входных значений к переменным. Лямбда - выражение может быть сформировано путем добавления λx .в передней части существующего выражения, например λx . x + 1. Переменная xназывается свободным в x + 1и связаны вλx . x + 1

Как это помогает в оценке выражений? Если вы передаете значение лямбда-выражению, например, так

(λx . x + 1) 2

затем вы можете оценить все выражение, заменив (связав) все вхождения переменной xзначением 2:

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

Итак, лямбда-нотация обеспечивает общий механизм для привязки вещей к переменным, которые появляются в блоке выражения / программы. В зависимости от контекста это создает совершенно разные понятия в языках программирования:

  • В чисто функциональном языке, таком как Haskell, лямбда-выражения представляют функции в математическом смысле: входное значение вводится в тело лямбда-выражения и создается выходное значение.
  • Во многих языках (например, JavaScript, Python, Scheme) оценка тела лямбда-выражения может иметь побочные эффекты. В этом случае можно использовать термин « процедура» для обозначения разницы относительно чистых функций.

Помимо различий, лямбда-нотация заключается в определении формальных параметров и их привязке к фактическим параметрам.

Следующий шаг - дать имя функции / процедуре. В нескольких языках функции являются значениями, как и любые другие, поэтому вы можете дать функции имя следующим образом:

(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

Как отметил Эли Барзилай, эти определения просто связывают имя fсо значением, которое оказывается функцией. Таким образом, в этом отношении функции, числа, строки, символы - это все значения, которые могут быть связаны с именами одинаково:

(define n 42)   ;; Scheme

n = 42          -- Haskell

val n: Int = 42 // Scala

var n = 42      // JavaScript

n = 42          # Python

В этих языках вы также можете привязать функцию к имени, используя более знакомую (но эквивалентную) запись:

(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

Некоторые языки, например C, поддерживают только последние обозначения для определения (именованных) функций.

Затворы

Несколько заключительных замечаний относительно замыканий . Рассмотрим выражение x + y. Это содержит две свободные переменные. Если вы связываете, xиспользуя лямбда-нотацию, вы получаете:

\x -> x + y

Это не (пока) функция, потому что она все еще содержит свободную переменную y. Вы можете сделать из него функцию, связав yтакже:

\x -> \y -> x + y

или же

\x y -> x + y

который так же, как +функция.

Но вы можете связать, скажем, yпо-другому (*):

incrementBy y = \x -> x + y

Результатом применения функции incrementBy к числу является замыкание, то есть функция / процедура, тело которой содержит свободную переменную (например y), которая была связана со значением из среды, в которой было определено замыкание.

Так же incrementBy 5как и функция (замыкание), которая увеличивает числа на 5.

НОТА (*)

Я немного обманываю здесь:

incrementBy y = \x -> x + y

эквивалентно

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

поэтому механизм связывания такой же. Интуитивно я думаю, что замыкание представляет часть более сложного лямбда-выражения. Когда это представление создано, некоторые из привязок материнского выражения уже были установлены, и замыкание использует их позже, когда оно будет оценено / вызвано.

Джорджио
источник
Я только начинающий, но я думаю, что это может немного сбить с толку, если вы пытаетесь понять исчисление λ в математическом смысле, поскольку то, что вы называете константами, называется переменными и обозначается символами a, b, c ... Что вы переменные вызова будут неопределенной переменной х . С другой стороны, 1 есть λ f x . f x , 2 является λ f x . f ( f x ) и так далее.
Джинави
@jinawee: Признаюсь, я не нашел точное определение. Я помню, как использовал термины переменные и константы в логике. Там константа - это символ, который сопоставляется с доменом, а переменная - это символ, который вы можете определить количественно. Но, опять же, (1) это давно прошло с тех пор, как я прошел курс по логике, и (2) лямбда-исчисление не должно следовать 1-1 понятиям математической логики. Если вы укажете мне ссылку, я могу попытаться исправить мою терминологию.
Джорджио
0

«Лямбда» в программировании обычно означает «лямбда-функцию» (или также «лямбда-выражение», «лямбда-термин»). Когда функция - это именованный блок кода, определенный до ее использования, «лямбда-функция» - это блок кода (или выражение), определенный вместо использования, который может использоваться как первоклассный гражданин в языке программирования.

В JavaScript ES6 (2015) есть короткий синтаксис для определения лямбд, называемый «Функции стрелок» . В C # такой синтаксис был введен в .NET 3.0 (около 2006 г.) .

В математике понятие «функция» имеет несколько значений, где одно из значений относится к нотации функции (т. Е. Как записать ее), тогда «лямбда-функция» (в исчислении) представляет собой особый вид нотации функции. Для более подробного обсуждения проверьте лямбда-функции в языках программирования .

battlmonstr
источник