在 javascript 中使用 filter() 实现 curriable() 是最终的,但是,使用 map() 是可行的,为什么?
Using filter() to implemnt curriable() in javascript is fial , however, uisng map() is work, why?
我正在尝试实现带有占位符支持的 curry(),即 curriable
。 curriable
提供了一种高性能和占用空间小的 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.
更密切相关
我正在尝试实现带有占位符支持的 curry(),即 curriable
。 curriable
提供了一种高性能和占用空间小的 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.