代码之家  ›  专栏  ›  技术社区  ›  Aadit M Shah

在JavaScript中反转默认参数的顺序

  •  0
  • Aadit M Shah  · 技术社区  · 6 年前

    我有以下递归 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

    现在,我要做的是推翻 组成 所以默认参数是第一个:

    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
    

    在默认参数优先的情况下,编写这样的函数最优雅的方法是什么?


    编辑: 我真的想创造 map ap 各种算术函数的方法,以便我可以编写:

    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); // (,) <$> (+) <*> (*)
    

    因此,我不想像贝基在他的回答中所建议的那样采用咖喱的方法。

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

    2 回复  |  直到 6 年前
        1
  •  1
  •   Bergi    6 年前

    在默认参数优先的情况下,编写这样的函数最优雅的方法是什么?

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

    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 .

        2
  •  2
  •   Bergi    6 年前

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

    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)))