什么时候 a => f(a) 不等同于 f?

When is a => f(a) not equivalent to f?

lodash 的新手并尝试使用它以获得更多理解。我不明白以下代码的行为。

了解 _.curry 的 arity 参数后,我有一个代码片段产生的结果对我来说似乎很奇怪。

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 的输出。在我看来,当需要一个 arg 函数时,我只是将 a => f(a) 替换为 f。

是的,JavaScript中的fa => 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),其中 beta 减少为 array(1),因为从未使用过 23。但是,非 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 是一个 array of three arguments、单词、索引和数组。因此,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