Неужели Immutable.js или Lazy.js выполняют короткое слияние?

Во-первых, позвольте мне определить, что short-cut fusion для тех из вас, кто этого не знает. Рассмотрим следующее преобразование массива в JavaScript:

var a = [1,2,3,4,5].map(square).map(increment);

console.log(a);

function square(x) {
    return x * x;
}

function increment(x) {
    return x + 1;
}

Ответ 1

Я автор Immutable.js(и поклонник Lazy.js).

Используются ли Lazy.js и Immutable.js Seq с помощью короткого замыкания? Нет, не совсем. Но они удаляют промежуточное представление результатов операции.

Сокращенное слияние - это метод компиляции/транспиляции кода. Ваш пример хороший:

var a = [1,2,3,4,5].map(square).map(increment);

Transpiled:

var a = [1,2,3,4,5].map(compose(square, increment));

Lazy.js и Immutable.js не являются передатчиками и не будут переписывать код. Это библиотеки времени выполнения. Таким образом, вместо короткого слияния (техника компилятора) они используют итеративный состав (техника времени исполнения).

Вы ответите на это в своем TL;DR:

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

Это точно.

Пусть распаковывается:

Массивы сохраняют промежуточные результаты при цепочке:

var a = [1,2,3,4,5];
var b = a.map(square); // b: [1,4,6,8,10] created in O(n)
var c = b.map(increment); // c: [2,5,7,9,11] created in O(n)

Трансляция с коротким разрезом создает промежуточные функции:

var a = [1,2,3,4,5];
var f = compose(square, increment); // f: Function created in O(1)
var c = a.map(f); // c: [2,5,7,9,11] created in O(n)

Итерируемая композиция создает промежуточные итерации:

var a = [1,2,3,4,5];
var i = lazyMap(a, square); // i: Iterable created in O(1)
var j = lazyMap(i, increment); // j: Iterable created in O(1)
var c = Array.from(j); // c: [2,5,7,9,11] created in O(n)

Обратите внимание, что с использованием итеративной композиции мы не создали хранилище промежуточных результатов. Когда эти библиотеки говорят, что они не создают промежуточных представлений, что они означают, именно то, что описано в этом примере. Структура данных не создается, сохраняя значения [1,4,6,8,10].

Однако, конечно, выполняется некоторое промежуточное представление. Каждая "ленивая" операция должна что-то вернуть. Они возвращают итерабельность. Их создание чрезвычайно дешево и не связано с размером данных, которые используются. Обратите внимание, что при короткой транскрипции слияния также производится промежуточное представление. Результатом compose является новая функция. Функциональный состав (рукописный или результат компилятора с коротким разрезом) очень связан с композицией Iterable.

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


Appx:

Вот что может выглядеть простая реализация lazyMap:

function lazyMap(iterable, mapper) {
  return {
    "@@iterator": function() {
      var iterator = iterable["@@iterator"]();
      return {
        next: function() {
          var step = iterator.next();
          return step.done ? step : { done: false, value: mapper(step.value) }
        }
      };
    }
  };
}