Compose - 函数式编程
Compose - functional programming
我想创建自己的 compose 实现
这个有效
const compose = (...fns) => fns.reduce((f,g) => (...args) => f(g(...args)));
这不是
const compose1 = (...fns) => (...args) => fns.reduce((f,g) => f(g(...args)));
.
const multi = a => x => x*a;
const devide = a => x => x/a;
const add = a => x => x+a;
compose(add(6), multi(4), devide(5))(5); // 10 as expected
compose1(add(6), multi(4), devide(5))(5); // Uncaught TypeError: f is not a function
你能解释一下为什么第二个实现不起作用吗?
通过将语法扩展为多行,您可以开始查看第二个函数中的问题所在。您正在调用 fns.reduce
,而您应该调用 args.reduce
。从那里开始,它仍然 returns 一个不同的值,所以很可能还有其他一些问题,但这只是一个开始。
第二个控制台日志还应显示 f
的值不是您期望的值。
理想情况下,您应该只为非常简单的操作编写 shorthand,或者为您已经以更易于阅读和测试的方式进行全面测试的内容编写。
const compose = (...fns) => {
return fns.reduce((f,g) => {
console.log('f: ',f,'g: ',g)
return (...args) => f(g(...args))
})
};
const compose1 = (...fns) => {
return (...args) => {
return args.reduce((f,g) => { //was fns.reduce
console.log('f: ',f,'g: ',g)
return f(g(...args))
})
}
}
const multi = a => x => x*a;
const devide = a => x => x/a;
const add = a => x => x+a;
var result1 = compose(add(6), multi(4), devide(5))(5); // 10 as expected
console.log(result1)
var result2 = compose1(add(6), multi(4), devide(5))(5); // Uncaught TypeError: f is not a function
console.log(result2)
要使您的版本正常运行,您需要执行以下操作:
const compose1 = (...fns) => (...args) => fns.reduceRight((res, f) => f(res), fns.pop()(...args))
你失败的原因是因为reduce
(和reduceRight
)接受了一个带有这个签名的函数:
(previousValue, currentValue) => newPreviousValue
解释:
在你的版本中发生的事情是,在第一次 reduce 调用你的函数后,newPreviousValue
现在不再是一个函数,它现在是 f(g(...args))
(最后一个函数调用的结果), 因此当 reduce 再次尝试 "call" 那个函数时,它使用上次调用的结果,就好像它是一个函数一样,所以你会得到错误。
如果你看到我上面的那个,res
就是previousValue
,这是最后一个函数调用的结果,但它没有被用作函数。
进一步
如果你想知道为什么它在第一次调用时就成功了,那么这是因为你没有为 reduce
提供初始值,所以它只是从列表作为函数的参数,它允许您执行:f(g(...args))
const compose = (...fns) => {
console.log('function', fns);
return fns.reduce((f,g) => {
console.log('f and g' , f,g)
return (...args) => {
console.log('args is ' , args)
return f(g(...args));
}
})
};
// call with
compose(add(6), multi(4), devide(5))(5);
将产生
VM1239:2 function (3) [ƒ, ƒ, ƒ]
VM1239:4 f and g x => x+a x => x*a
VM1239:4 f and g (...args) => {
console.log('args is ' , args)
return f(g(...args));
} x => x/a
VM1239:6 args is [5]
VM1239:6 args is [1]
10
一切正常
对你的 compose1
做同样的事情
const compose1 = (...fns) => {
console.log('functions ', fns)
return (...args) => {
console.log('args', args)
return fns.reduce((f,g) => {
console.log('f and g', f,g)
return f(g(...args))
})
}
};
//called with
compose1(add(6), multi(4), devide(5))(5)
将产生
VM1783:2 functions (3) [ƒ, ƒ, ƒ]
0: x => x+a
1: x => x*a
2: x => x/a
VM1783:4 args [5]
VM1783:6 f and g x => x+a x => x*a
VM1783:6 f and g 26 x => x/a
VM1783:7 Uncaught TypeError: f is not a function
at fns.reduce (<anonymous>:7:14)
at Array.reduce (<anonymous>)
at args (<anonymous>:5:16)
at <anonymous>:1:38
所以你的 f
现在是 26,这不是一个函数:)
解释:
you called
f (g (...args))
f ( g ( 5 ) )
f ( 5 * a) // a is 4
f ( 20 )
16 + a // a is 6
26
让我们通过分解来看看你的compose1
:
const compose1 = (...fns) => {
// Returns a function that reduces fns each time it is called
return (...args) => {
// Returns the reduction of fns
return fns.reduce((f,g) => {
// Returns the result of calling f(g(...args))
return f(g(...args))
})
}
};
现在让我们看一下这个版本的 compose 的示例调用:
compose1(add(6), multi(4), devide(5))(5);
首先,我们调用compose1
。这个returns这个函数:
(...args) => {
// Returns the reduction of fns
return fns.reduce((f,g) => {
// Returns the result of calling f(g(...args))
return f(g(...args))
})
}
然后我们用参数5
调用这个函数,本质上就是像之前返回的函数一样调用fns.reduce
。要查看到底出了什么问题,让我们 运行 通过 reduce 的几次迭代:
第一次迭代:
fns.reduce((f = add(6), g = multi(4)) => {
// Returns the result of calling f(g(...args))
return f(g(...args = [5]))
// g is `multi(4)`, so do `multi(4)(5)`, which returns 20. Next:
// f is `add(6)`, so do `add(6)(20)`, which returns 26.
// Remember that the return from last iteration is
// the first parameter of the next iteration
})
第二次迭代:
fns.reduce((f = 26, g = devide(5)) => {
// Returns the result of calling f(g(...args))
return f(g(...args = [5]))
// g is `devide(5)`, so do `devide(5)(5)`, which returns 1. Next:
// f is 26, so do `26(1)`. However, 26 is not a function.
// You get the error `f is not a function`.
})
我想创建自己的 compose 实现
这个有效
const compose = (...fns) => fns.reduce((f,g) => (...args) => f(g(...args)));
这不是
const compose1 = (...fns) => (...args) => fns.reduce((f,g) => f(g(...args)));
.
const multi = a => x => x*a;
const devide = a => x => x/a;
const add = a => x => x+a;
compose(add(6), multi(4), devide(5))(5); // 10 as expected
compose1(add(6), multi(4), devide(5))(5); // Uncaught TypeError: f is not a function
你能解释一下为什么第二个实现不起作用吗?
通过将语法扩展为多行,您可以开始查看第二个函数中的问题所在。您正在调用 fns.reduce
,而您应该调用 args.reduce
。从那里开始,它仍然 returns 一个不同的值,所以很可能还有其他一些问题,但这只是一个开始。
第二个控制台日志还应显示 f
的值不是您期望的值。
理想情况下,您应该只为非常简单的操作编写 shorthand,或者为您已经以更易于阅读和测试的方式进行全面测试的内容编写。
const compose = (...fns) => {
return fns.reduce((f,g) => {
console.log('f: ',f,'g: ',g)
return (...args) => f(g(...args))
})
};
const compose1 = (...fns) => {
return (...args) => {
return args.reduce((f,g) => { //was fns.reduce
console.log('f: ',f,'g: ',g)
return f(g(...args))
})
}
}
const multi = a => x => x*a;
const devide = a => x => x/a;
const add = a => x => x+a;
var result1 = compose(add(6), multi(4), devide(5))(5); // 10 as expected
console.log(result1)
var result2 = compose1(add(6), multi(4), devide(5))(5); // Uncaught TypeError: f is not a function
console.log(result2)
要使您的版本正常运行,您需要执行以下操作:
const compose1 = (...fns) => (...args) => fns.reduceRight((res, f) => f(res), fns.pop()(...args))
你失败的原因是因为reduce
(和reduceRight
)接受了一个带有这个签名的函数:
(previousValue, currentValue) => newPreviousValue
解释:
在你的版本中发生的事情是,在第一次 reduce 调用你的函数后,newPreviousValue
现在不再是一个函数,它现在是 f(g(...args))
(最后一个函数调用的结果), 因此当 reduce 再次尝试 "call" 那个函数时,它使用上次调用的结果,就好像它是一个函数一样,所以你会得到错误。
如果你看到我上面的那个,res
就是previousValue
,这是最后一个函数调用的结果,但它没有被用作函数。
进一步
如果你想知道为什么它在第一次调用时就成功了,那么这是因为你没有为 reduce
提供初始值,所以它只是从列表作为函数的参数,它允许您执行:f(g(...args))
const compose = (...fns) => {
console.log('function', fns);
return fns.reduce((f,g) => {
console.log('f and g' , f,g)
return (...args) => {
console.log('args is ' , args)
return f(g(...args));
}
})
};
// call with
compose(add(6), multi(4), devide(5))(5);
将产生
VM1239:2 function (3) [ƒ, ƒ, ƒ]
VM1239:4 f and g x => x+a x => x*a
VM1239:4 f and g (...args) => {
console.log('args is ' , args)
return f(g(...args));
} x => x/a
VM1239:6 args is [5]
VM1239:6 args is [1]
10
一切正常
对你的 compose1
const compose1 = (...fns) => {
console.log('functions ', fns)
return (...args) => {
console.log('args', args)
return fns.reduce((f,g) => {
console.log('f and g', f,g)
return f(g(...args))
})
}
};
//called with
compose1(add(6), multi(4), devide(5))(5)
将产生
VM1783:2 functions (3) [ƒ, ƒ, ƒ]
0: x => x+a
1: x => x*a
2: x => x/a
VM1783:4 args [5]
VM1783:6 f and g x => x+a x => x*a
VM1783:6 f and g 26 x => x/a
VM1783:7 Uncaught TypeError: f is not a function
at fns.reduce (<anonymous>:7:14)
at Array.reduce (<anonymous>)
at args (<anonymous>:5:16)
at <anonymous>:1:38
所以你的 f
现在是 26,这不是一个函数:)
解释:
you called
f (g (...args))
f ( g ( 5 ) )
f ( 5 * a) // a is 4
f ( 20 )
16 + a // a is 6
26
让我们通过分解来看看你的compose1
:
const compose1 = (...fns) => {
// Returns a function that reduces fns each time it is called
return (...args) => {
// Returns the reduction of fns
return fns.reduce((f,g) => {
// Returns the result of calling f(g(...args))
return f(g(...args))
})
}
};
现在让我们看一下这个版本的 compose 的示例调用:
compose1(add(6), multi(4), devide(5))(5);
首先,我们调用compose1
。这个returns这个函数:
(...args) => {
// Returns the reduction of fns
return fns.reduce((f,g) => {
// Returns the result of calling f(g(...args))
return f(g(...args))
})
}
然后我们用参数5
调用这个函数,本质上就是像之前返回的函数一样调用fns.reduce
。要查看到底出了什么问题,让我们 运行 通过 reduce 的几次迭代:
第一次迭代:
fns.reduce((f = add(6), g = multi(4)) => {
// Returns the result of calling f(g(...args))
return f(g(...args = [5]))
// g is `multi(4)`, so do `multi(4)(5)`, which returns 20. Next:
// f is `add(6)`, so do `add(6)(20)`, which returns 26.
// Remember that the return from last iteration is
// the first parameter of the next iteration
})
第二次迭代:
fns.reduce((f = 26, g = devide(5)) => {
// Returns the result of calling f(g(...args))
return f(g(...args = [5]))
// g is `devide(5)`, so do `devide(5)(5)`, which returns 1. Next:
// f is 26, so do `26(1)`. However, 26 is not a function.
// You get the error `f is not a function`.
})