Когда a => f (a) не эквивалентно f? - PullRequest
6 голосов
/ 06 мая 2019

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

После изучения аргумента arity для _.curry у меня есть фрагмент кода, который дает результаты, которые кажутся мне странными.

const words = ['jim', 'john'];
const pad10 = words =>
    _.map(words, word => _.pad(word, 10));

console.log(pad10(words)); // [ '   jim    ', '   john   ' ]

const flipMap = _.flip(_.map);
const flipPad = _.flip(_.pad);

const curriedFlipMap = _.curry(flipMap, 2);

const pad10v2 = curriedFlipMap(word => flipPad(' ', 10, word));

console.log(pad10v2(words)); // [ '   jim    ', '   john   ' ]

const curriedFlipPad = _.curry(flipPad, 3);
const padWord10 = curriedFlipPad(' ', 10);
const pad10v3 = curriedFlipMap(word => padWord10(word));

console.log(pad10v3(words)); // [ '   jim    ', '   john   ' ]

const pad10v4 = curriedFlipMap(padWord10);
console.log(pad10v4(words)); // [ 'jim,john', 'jim,john' ]
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Я не понимаю вывод последнего файла console.log. Похоже, я просто заменяю a => f (a) на f, когда ожидается функция с одним аргументом.

1 Ответ

3 голосов
/ 06 мая 2019

Да, в JavaScript есть разница между f и a => f(a).Рассмотрим следующий пример:

const array = (...args) => args;

const arrayEta = a => array(a);

console.log(array(1, 2, 3)); // [1, 2, 3]

console.log(arrayEta(1, 2, 3)); // [1]

Вы видите проблему?Когда я звоню arrayEta(1, 2, 3), он расширяется до (a => array(a))(1, 2, 3), а бета уменьшается до array(1), потому что 2 и 3 никогда не используются.Тем не менее, расширенная версия не является eta array(1, 2, 3).Это проблема с вашим кодом:

const words = ["jim", "john"];

const flipMap = _.flip(_.map);
const flipPad = _.flip(_.pad);

const curriedFlipMap = _.curry(flipMap, 2);
const curriedFlipPad = _.curry(flipPad, 3);

const padWord10 = curriedFlipPad(" ", 10);

const pad10v4 = curriedFlipMap((...args) => {
    console.log(args); // args is an array of 3 arguments
    return padWord10(...args);
});

console.log(pad10v4(words)); // ["jim,john", "jim,john"]
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Обратите внимание, что args - это массив из трех аргументов , word, index и array.Следовательно, curriedFlipMap(padWord10) фактически является эквивалентом curriedFlipMap((word, index, array) => padWord10(word, index, array)).Это не эквивалентно curriedFlipMap(word => padWord10(word)).

Следовательно, ваш вызов функции уменьшается следующим образом:

  padWord10("jim", 0, ["jim", "john"])
= curriedFlipPad(" ", 10)("jim", 0, ["jim", "john"])
= _curry(flipPad, 3)(" ", 10)("jim", 0, ["jim", "john"])
= _.pad(["jim", "john"], 0, "jim", 10, " ")
= _.pad(["jim", "john"], 0, "jim")

Как видите, вы предоставляете функцию _.pad 5аргументы, из которых он игнорирует последние 2. Следовательно, он преобразует ["jim", "john"] в строку, а затем добавляет к ней заполнение.

В любом случае, решение состоит в том, чтобы не делать eta-преобразование в этом случае.Кстати, если вы хотите использовать Lodash для функционального программирования, используйте вместо этого lodash/fp.

...