Что такое «Лямбда-лифтинг»? - PullRequest
38 голосов
/ 27 февраля 2009

Я только что натолкнулся на это, просматривая исходный код компилятора Erlang.

Я не совсем понимаю. (пойди разберись;)), учитывая, что я только что понял, что такое есть 5 минут назад).

Простите, что сначала спросил, не пытаясь понять причины его существования.

Существует статья википедии , но она довольно загадочная.

Ответы [ 4 ]

48 голосов
/ 27 февраля 2009

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

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

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

38 голосов
/ 27 февраля 2009

Лямбда-лифтинг - это техника для подъема лямбд на более высокий уровень (в основном на верхний уровень).

Даг Керри описывает, почему вы хотите это сделать.

Вот пример кода (в JavaScript), как вы могли бы сделать это вручную:

function addFive(nr)
{
  var x = 5;
  function addX(y)
  {
    return x + y;
  }

  return addX(nr);
}

Теперь, если вам не нужна эта addX функция в определении addFive, вы можете "поднять" ее на верхний уровень следующим образом:

function addX(y)
{
  return x + y;
}

function addFive(nr)
{
  var x = 5;

  return addX(nr);
}

Однако это не сработает, поскольку переменная x больше не доступна в контексте функции addX. Чтобы исправить это, добавьте в функцию дополнительный формальный параметр:

function addX(y, x)
{
  return x + y;
}

function addFive(nr)
{
  var x = 5;

  return addX(nr, x);
}

Добавление: Вот очень надуманный пример лямбда-экранирования. Там, где вы не сможете выполнять лямбда-подъем так же легко, как я описал.

function getAddFiveFunc()
{
  var x = 5;
  function addX(y)
  {
    return x + y;
  }

  return addX;
}

Теперь, если кто-то вызовет функцию getAddFiveFunc, он получит функцию обратно. Эту функцию можно использовать во всех местах. Теперь, если вы хотите отменить функцию addX, вам придется обновить все эти места вызова.

1 голос
/ 27 февраля 2009

Предупреждение: мой ответ на самом деле описывает захваченные переменные, которые отличаются от лямбда-лифтинга. Неправильно прочитанный вопрос (нужно спать). Но я потратил немного времени на написание этого, поэтому мне не хочется его удалять. Оставь это как сообщество WIKI.

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

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

Я сосредоточусь на C #, поскольку это, вероятно, язык, наиболее распространенный для читателей переполнения стека. Начнем со следующего кода.

public Func<int> GetAFunction() {
  var x = 42;
  Func<int> lambda1 = () => x;
  Func<int> lambda2 = () => 42;
  ...
  return lambda1;
}

В этом примере мы создали 2 лямбда-выражения. В обоих случаях он присваивается экземпляру делегата типа Func. Все делегаты в .Net требуют, чтобы реальная функция поддерживала их где-то. Таким образом, под капотом все лямбда-выражения / анонимные функции в C # переводятся в определение метода.

Создать функцию для lambda2 довольно просто. Это изолированная функция, которая просто возвращает постоянное значение.

public static int RealLambda2() { 
  return 42;
}

Генерировать lambda1 немного сложнее. Литеральное определение будет выглядеть следующим образом

public static int RealLambda1() {
  return x;
}

Это, очевидно, не скомпилируется, потому что x не доступен. Для этого компилятор C # должен поднять переменную x в замыкание. Затем он может вернуть указатель на функцию в замыкании, чтобы удовлетворить выражение делегата

class Closure1 {
  int x;
  public int RealLambda1() {
    return x;
  }
}

Это довольно простой пример, но, надо надеяться, должен детализировать искусство подъема. К сожалению, дьявол кроется в деталях и все усложняет сценарий.

0 голосов
/ 27 февраля 2009

лямбда-лифтинг в основном устраняет переменные и помещает их в чистые функции, упрощая выполнение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...