如何正确柯里化这个函数?
How do I curry this function correctly?
我尝试使用 curryDecorate
柯里化函数 add
const curryDecorate = (fn, ...args) => {
const curried = (...newArgs) => {
args = args.concat(newArgs)
if (args.length < fn.length) {
return curried
}
return fn(...args)
}
return curried
}
const add = (a, b, c) => a + b + c
const sum = curryDecorate(add)
console.log(sum(1)(2)(3)) // 6
console.log(sum(1, 2)(3)) // 6
console.log(sum(1)(2, 3)) // 6
当sum(1, 2)(3)
为运行时,我得到
sum(...) is not a function
运行单独设置底部3行时正常,
但一起抛出该错误。
您正在使用 sum
变量两次进行柯里化,这只会保存一组参数。
sum(1)(2)(3) // args: 1, 2, 3
sum(1, 2) // persists, so args: 1, 2, 3, 1, 2
这解决了您的问题:
const curryDecorate = (fn, ...args) => {
let pass=[...args];
const curried = (...newArgs) => {
pass= pass.concat(newArgs)
if (pass.length < fn.length) {
return curried
}
const val = fn(...pass);
pass=[...args]
return val;
}
return curried
}
const add = (a, b, c) => a + b + c
const sum = curryDecorate(add)
console.log(sum(1)(2)(3)) // 6
console.log(sum(1, 2)(3)) // 6
console.log(sum(1)(2, 3)) // 6
const curryDecorate = (fn, ...args) => {
const curried = (...newArgs) => {
args = args.concat(newArgs)
console.log('fn len', fn.length, args.length, args.length < fn.length)
if (args.length < fn.length){
return curried
}
const currArgs = [...args]
args = []
return fn(...currArgs)
}
return curried
}
const add = (a, b, c) => console.log(a + b + c)
const sum = curryDecorate(add)
sum(1)(2)(3)
sum(1)(2)(3)
sum(1)(2)(3)
sum(1)(2)(3)
sum(1)(2)(3)
// 6
问题是您目前只有一个 args
的实例,它在修饰的柯里化函数的所有版本之间共享。这意味着一旦你获得足够的参数 once 任何进一步的 curried 调用将直接进入 return fn(...args)
并且因此再次执行将失败:
console.log(sum (1) (2) (3))
// ^^^ ^^^ ^^^
// | | |
//args = [1] -----------------+ | |
//args = [1, 2] ------------------+ |
//args = [1, 2, 3] -------------------+
console.log(sum (1, 2) (3))
// ^^^^^^
// |
//args = [1, 2, 3, 1, 2] ------+
在第四次调用 sum(1, 2)
时,args
数组包含 [1, 2, 3, 1, 2]
,比 fn.length
多 ,因此 sum(1, 2)
将执行函数和 return 6
。下一个 (3)
将尝试将数字作为函数执行并失败:
const curryDecorate = (fn, ...args) => {
const curried = (...newArgs) => {
args = args.concat(newArgs)
if (args.length < fn.length) {
return curried
}
return fn(...args)
}
return curried
}
const add = (a, b, c) => a + b + c
const sum = curryDecorate(add)
console.log(sum(1)(2)(3)) // 6
const result = sum(1, 2);
console.log(result) // 6
console.log(result(3)) // error
您可以利用 curryDecorate
已经将 args
作为参数这一事实来避免此错误。如果 curried 调用不满足参数要求,您可以使用到目前为止的所有参数再次调用 curryDecorate
。这样你就可以得到单独的函数对象,每个函数对象都有一个单独的部分填充的参数列表:
const curryDecorate = (fn, ...args) => {
const curried = (...newArgs) => {
//collect all into newArgs
newArgs = args.concat(newArgs)
if (newArgs.length < fn.length) {
//call curryDecorate with arguments so far
return curryDecorate(fn, ...newArgs)
}
//execute with all collected args
return fn(...newArgs)
}
return curried
}
const add = (a, b, c) => a + b + c
const sum = curryDecorate(add)
console.log(sum(1)(2)(3)) // 6
console.log(sum(1, 2)(3)) // 6
console.log(sum(1)(2, 3)) // 6
console.log("-----");
const sum1 = sum(1);
const sum14 = sum1(4);
const sum15 = sum1(5);
const sum144 = sum14(4);
const sum145 = sum14(5);
const sum155 = sum15(5);
const sum156 = sum15(6);
console.log(sum144);
console.log(sum145);
console.log(sum155);
console.log(sum156);
.as-console-wrapper { max-height: 100% !important; }
再往前走一步,如果 curryDecorate
无论如何都要用参数调用,执行或不执行函数的逻辑可以移到那里,事情会简化一点:
const curryDecorate = (fn, ...args) => {
if (args.length >= fn.length)
return fn(...args);
return (...newArgs) =>
curryDecorate(fn, ...args, ...newArgs);
}
const curryDecorate = (fn, ...args) => {
if (args.length >= fn.length)
return fn(...args);
return (...newArgs) =>
curryDecorate(fn, ...args, ...newArgs);
}
const add = (a, b, c) => a + b + c
const sum = curryDecorate(add)
console.log(sum(1)(2)(3)) // 6
console.log(sum(1, 2)(3)) // 6
console.log(sum(1)(2, 3)) // 6
console.log("-----");
const sum1 = sum(1);
const sum14 = sum1(4);
const sum15 = sum1(5);
const sum144 = sum14(4);
const sum145 = sum14(5);
const sum155 = sum15(5);
const sum156 = sum15(6);
console.log(sum144);
console.log(sum145);
console.log(sum155);
console.log(sum156);
.as-console-wrapper { max-height: 100% !important; }
我尝试使用 curryDecorate
add
const curryDecorate = (fn, ...args) => {
const curried = (...newArgs) => {
args = args.concat(newArgs)
if (args.length < fn.length) {
return curried
}
return fn(...args)
}
return curried
}
const add = (a, b, c) => a + b + c
const sum = curryDecorate(add)
console.log(sum(1)(2)(3)) // 6
console.log(sum(1, 2)(3)) // 6
console.log(sum(1)(2, 3)) // 6
当sum(1, 2)(3)
为运行时,我得到
sum(...) is not a function
运行单独设置底部3行时正常, 但一起抛出该错误。
您正在使用 sum
变量两次进行柯里化,这只会保存一组参数。
sum(1)(2)(3) // args: 1, 2, 3
sum(1, 2) // persists, so args: 1, 2, 3, 1, 2
这解决了您的问题:
const curryDecorate = (fn, ...args) => {
let pass=[...args];
const curried = (...newArgs) => {
pass= pass.concat(newArgs)
if (pass.length < fn.length) {
return curried
}
const val = fn(...pass);
pass=[...args]
return val;
}
return curried
}
const add = (a, b, c) => a + b + c
const sum = curryDecorate(add)
console.log(sum(1)(2)(3)) // 6
console.log(sum(1, 2)(3)) // 6
console.log(sum(1)(2, 3)) // 6
const curryDecorate = (fn, ...args) => {
const curried = (...newArgs) => {
args = args.concat(newArgs)
console.log('fn len', fn.length, args.length, args.length < fn.length)
if (args.length < fn.length){
return curried
}
const currArgs = [...args]
args = []
return fn(...currArgs)
}
return curried
}
const add = (a, b, c) => console.log(a + b + c)
const sum = curryDecorate(add)
sum(1)(2)(3)
sum(1)(2)(3)
sum(1)(2)(3)
sum(1)(2)(3)
sum(1)(2)(3)
// 6
问题是您目前只有一个 args
的实例,它在修饰的柯里化函数的所有版本之间共享。这意味着一旦你获得足够的参数 once 任何进一步的 curried 调用将直接进入 return fn(...args)
并且因此再次执行将失败:
console.log(sum (1) (2) (3))
// ^^^ ^^^ ^^^
// | | |
//args = [1] -----------------+ | |
//args = [1, 2] ------------------+ |
//args = [1, 2, 3] -------------------+
console.log(sum (1, 2) (3))
// ^^^^^^
// |
//args = [1, 2, 3, 1, 2] ------+
在第四次调用 sum(1, 2)
时,args
数组包含 [1, 2, 3, 1, 2]
,比 fn.length
多 ,因此 sum(1, 2)
将执行函数和 return 6
。下一个 (3)
将尝试将数字作为函数执行并失败:
const curryDecorate = (fn, ...args) => {
const curried = (...newArgs) => {
args = args.concat(newArgs)
if (args.length < fn.length) {
return curried
}
return fn(...args)
}
return curried
}
const add = (a, b, c) => a + b + c
const sum = curryDecorate(add)
console.log(sum(1)(2)(3)) // 6
const result = sum(1, 2);
console.log(result) // 6
console.log(result(3)) // error
您可以利用 curryDecorate
已经将 args
作为参数这一事实来避免此错误。如果 curried 调用不满足参数要求,您可以使用到目前为止的所有参数再次调用 curryDecorate
。这样你就可以得到单独的函数对象,每个函数对象都有一个单独的部分填充的参数列表:
const curryDecorate = (fn, ...args) => {
const curried = (...newArgs) => {
//collect all into newArgs
newArgs = args.concat(newArgs)
if (newArgs.length < fn.length) {
//call curryDecorate with arguments so far
return curryDecorate(fn, ...newArgs)
}
//execute with all collected args
return fn(...newArgs)
}
return curried
}
const add = (a, b, c) => a + b + c
const sum = curryDecorate(add)
console.log(sum(1)(2)(3)) // 6
console.log(sum(1, 2)(3)) // 6
console.log(sum(1)(2, 3)) // 6
console.log("-----");
const sum1 = sum(1);
const sum14 = sum1(4);
const sum15 = sum1(5);
const sum144 = sum14(4);
const sum145 = sum14(5);
const sum155 = sum15(5);
const sum156 = sum15(6);
console.log(sum144);
console.log(sum145);
console.log(sum155);
console.log(sum156);
.as-console-wrapper { max-height: 100% !important; }
再往前走一步,如果 curryDecorate
无论如何都要用参数调用,执行或不执行函数的逻辑可以移到那里,事情会简化一点:
const curryDecorate = (fn, ...args) => {
if (args.length >= fn.length)
return fn(...args);
return (...newArgs) =>
curryDecorate(fn, ...args, ...newArgs);
}
const curryDecorate = (fn, ...args) => {
if (args.length >= fn.length)
return fn(...args);
return (...newArgs) =>
curryDecorate(fn, ...args, ...newArgs);
}
const add = (a, b, c) => a + b + c
const sum = curryDecorate(add)
console.log(sum(1)(2)(3)) // 6
console.log(sum(1, 2)(3)) // 6
console.log(sum(1)(2, 3)) // 6
console.log("-----");
const sum1 = sum(1);
const sum14 = sum1(4);
const sum15 = sum1(5);
const sum144 = sum14(4);
const sum145 = sum14(5);
const sum155 = sum15(5);
const sum156 = sum15(6);
console.log(sum144);
console.log(sum145);
console.log(sum155);
console.log(sum156);
.as-console-wrapper { max-height: 100% !important; }