问题描述
我尝试使用 add
curryDecorate
进行柯里化
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(...) 不是函数
分别运行底部的 3 行时它可以正常工作, 但一起它会抛出那个错误。
解决方法
您使用了两次 sum
变量来进行柯里化,这只会保存一组参数。
sum(1)(2)(3) // args: 1,2,3
sum(1,2) // persists,so args: 1,3,1,2
,
这可以解决您的问题:
TextBox
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
的单个实例,该实例在所有版本的装饰柯里化函数之间共享。这意味着一旦您获得足够的参数一次,任何进一步的柯里化调用都将直接转到 return fn(...args)
,因此再次执行将失败:
console.log(sum (1) (2) (3))
// ^^^ ^^^ ^^^
// | | |
//args = [1] -----------------+ | |
//args = [1,2] ------------------+ |
//args = [1,3] -------------------+
console.log(sum (1,2) (3))
// ^^^^^^
// |
//args = [1,2] ------+
在第四次调用 sum(1,2)
时,args
数组包含的 [1,2]
比 fn.length
更多,因此 sum(1,2)
将执行函数并返回 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,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
作为参数的事实,以避免此错误。如果柯里化调用不满足参数要求,您可以使用到目前为止的所有参数再次调用 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,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,...newArgs);
}
const add = (a,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; }