在 javascript 中使用 filter() 实现 curriable() 是最终的,但是,使用 map() 是可行的,为什么?

Using filter() to implemnt curriable() in javascript is fial , however, uisng map() is work, why?

我正在尝试实现带有占位符支持的 curry(),即 curriablecurriable 提供了一种高性能和占用空间小的 curry 方法。 version1 是工作代码 在递归函数中使用 map 。但是,我在version2中尝试使用filter来过滤placeholder!在大多数情况下,使用过滤器是好的,但由于 curriedJoin(_,_,3,4)(1,_)(2,5) 的原因 Uncaught TypeError: curriedJoin(...)(...) is not a function 而失败,任何人都可以告诉我为什么吗?

版本 1

/**
 * @param { (...args: any[]) => any } fn
 * @returns { (...args: any[]) => any }
 */
// function curry(fn) {
//   // your code here
// }

function curry(func) {
  return function curried(...args) {
    const complete = args.length >= func.length && !args.slice(0, func.length).includes(curry.placeholder);
    
    if(complete) {
      args.length=3
      args.sort((a,b)=>a-b)
      return func.apply(this, args)
    }
    return function(...newArgs) {
      // replace placeholders in args with values from newArgs using map
      const res = args.map(arg => arg === curry.placeholder && newArgs.length ? newArgs.shift() : arg);
      return curried(...res, ...newArgs);
    }
  }
}
const  join = (a, b, c) => {
   return `${a}_${b}_${c}`
}

curry.placeholder = Symbol()

const curriedJoin = curry(join)
const _ = curry.placeholder

console.log(curriedJoin(1, 2, 3)) // '1_2_3'
console.log(curriedJoin(_, 2)(1, 3)) // '1_2_3'
console.log(curriedJoin(_, _, _)(1)(_, 3)(2)) // '1_2_3'
console.log(curriedJoin(_,_,3,4)(1,_)(2,5))// '1_2_3'

版本 2

/**
 * @param { (...args: any[]) => any } fn
 * @returns { (...args: any[]) => any }
 */
// function curry(fn) {
//   // your code here
// }

function curry(func) {
  return function curried(...args) {
    const complete = args.length >= func.length && !args.slice(0, func.length).includes(curry.placeholder);
    
    if(complete) {
      args.length=3
      args.sort((a,b)=>a-b)
       return func.apply(this, args)
    }
    return function(...newArgs) {
      // replace placeholders in args with values from newArgs
      const res = [...args].filter(element=> element!== curry.placeholder);
      return curried(...res, ...newArgs);
    }
  }
}
const  join = (a, b, c) => {
   return `${a}_${b}_${c}`
}

curry.placeholder = Symbol()

const curriedJoin = curry(join)
const _ = curry.placeholder

console.log(curriedJoin(1, 2, 3)) // '1_2_3'
console.log(curriedJoin(_, 2)(1, 3)) // '1_2_3'
console.log(curriedJoin(_, _, _)(1)(_, 3)(2)) // '1_2_3'
console.log(curriedJoin(_,_,3,4)(1,_)(2,5)) //Fail, because "Uncaught TypeError: curriedJoin(...)(...) is not a function"

如果你添加

console.log(curriedJoin(_,_,3,4)(1,_));

就在失败行之前,您会看到 curriedJoin(_, _, 3, 4)(1, _) 已经解析为字符串“1_3_4”...这不是一个功能。因此错误。这两个版本的行为完全不同(在处理过程中记录各种参数列表很有启发性。)使用“过滤和附加”方法的问题是它没有按正确的顺序放置参数。对于失败的示例,在一次迭代后,第 3 个占位符最终位于 arg 列表的末尾,超出了“完整”测试正在检查的位置,而不是位于它所属的第 2 个位置。过滤时发生的情况是 (_, _, 3, 4)(1, _) 变为 (3,4,1,_),但函数只需要 3 个好的参数,所以这看起来“完整”- 哎呀!当使用“map”算法时,(_, _, 3, 4)(1, _) 变成(1, _, 3, 4) 显然不完整,因此它进入了另一个递归级别。

.sort 的使用涉及参数 的比较,并且不会将参数应用到它们应用的 位置 。使用 args.length = 3 将仅支持具有 3 个参数的函数。

添加参数 n = f.length 支持柯里化 fixed-arity 函数以及可变参数函数。添加具有合理归纳推理的 curry.merge 可简化合并参数并降低 curry.

的复杂性

function curry(f, n = f.length) {
  return function loop(...args) {
    const a = args.slice(0, n)
    return a.some(v => v === curry.placeholder)
      ? (...b) => loop(...curry.merge(a, b))
      : f(...a)
  }
}
curry.placeholder = Symbol("curry.placeholder")
curry.merge = (l, r) =>
  l.length == 0 && r.length == 0
    ? []
  : l.length == 0
    ? r
  : r.length == 0
    ? l
  : l[0] === curry.placeholder
    ? [r[0], ...curry.merge(l.slice(1), r.slice(1))]
  : [l[0], ...curry.merge(l.slice(1), r)]

const _ = curry.placeholder

const add = curry((a,b,c) => a + b + c)
console.log(add(1, 2, 3))             // 6
console.log(add(_, 2)(1, 3))          // 6
console.log(add(_, _, _)(1)(_, 3)(2)) // 6
console.log(add(_,_,3,4)(1,_)(2,5))   // 6

const foo = curry(console.log, 3)
foo(1, 2, 3)             // 1 2 3
foo(_, 2)(1, 3)          // 1 2 3
foo(_, _, _)(1)(_, 3)(2) // 1 2 3
foo(_,_,3,4)(1,_)(2,5)   // 1 2 3

也许 curry 更好的名称是 partial,因为您在这里使用的技术与 Partial Application.

更密切相关