反转JavaScript中默认参数的顺序

时间:2018-08-04 14:40:45

标签: javascript functional-programming default default-value

我具有以下递归compose函数:

const compose = (f, n = 1) => n > 1 ?
    compose(compose(f), n - 1) :
    g => x => f(g(x));

const length = a => a.length;

const filter = p => a => a.filter(p);

const countWhere = compose(length, 2)(filter);

const odd = n => n % 2 === 1;

console.log(countWhere(odd)([1,2,3,4,5,6,7,8,9])); // 5

现在,我想做的是翻转compose的参数,以便默认参数为first:

const compose = (n = 1, f) => n > 1 ? // wishful thinking
    compose(n - 1, compose(f)) : // compose(f) is the same as compose(1, f)
    g => x => f(g(x));

const length = a => a.length;

const filter = p => a => a.filter(p);

const countWhere = compose(2, length)(filter); // I want to call it like this

const odd = n => n % 2 === 1;

console.log(countWhere(odd)([1,2,3,4,5,6,7,8,9])); // 5

写这样的函数的最优雅的方法是什么,默认参数在前?


编辑:我实际上是想创建各种Arity函数的mapap方法,以便编写:

const length = a => a.length;

const filter = p => a => a.filter(p);

const countWhere = length.map(2, filter); // length <$> filter

const pair = x => y => [x, y];

const add = x => y => x + y;

const mul = x => y => x * y;

const addAndMul = pair.map(2, add).ap(2, mul); // (,) <$> (+) <*> (*)

因此,我不想像Bergi在他的回答中建议的那样使用这些方法。

有关更多信息,请阅读:Is implicit wrapping and unwrapping of newtypes in Haskell a sound idea?

2 个答案:

答案 0 :(得分:2)

我建议不要重载函数或使用默认参数:

const compose = n => f => n > 1
  ? compose(n - 1)(composeOne(f))
  : g => x => f(g(x));
const composeOne = compose(1);

在这种情况下,您也可以内联它,因为看来composeOne不会在其他任何地方被调用:

const compose = n => f => n > 1
  ? compose(n - 1)(compose(1)(f))
  : g => x => f(g(x));

甚至根本不进行递归调用,但始终创建​​g => x => … lambda并有条件地对其进行转换:

const compose = n => f => {
  const l = g => x => f(g(x));
  return n > 1 ? compose(n - 1)(l) : l;
};
// same without temporary variables:
const id = x => x;
const compose = n => f => (n > 1 ? compose(n-1) : id)(g => x => f(g(x)))

答案 1 :(得分:1)

  

写这样的函数的最优雅的方法是什么,默认参数在前?

仅使用默认初始化程序需要一些神秘的黑客手段:

function demo(n, f = [n, n = 1][0]) {
    console.log(n, f);
}
demo(2, "f"); // 2 f
demo("g"); // 1 g
console.log(demo.length) // 1

最直接的方法是使用条件运算符进行破坏:

function demo(...args) {
    const [n, f] = args.length < 2 ? [1, ...args] : args;
    console.log(n, f);
}
demo(2, "f"); // 2 f
demo("g"); // 1 g
console.log(demo.length) // 0

更多地本着“颠倒参数顺序”的精神,实际上是这样做的:

function demo(...args) {
    const [f, n = 1] = args.reverse();
    console.log(n, f);
}
demo(2, "f"); // 2 f
demo("g"); // 1 g
console.log(demo.length) // 0

后两次尝试的缺点是需要额外的声明(阻止我们使用简洁的箭头函数),并且没有在.length中反映实际的数量或所需的参数。