03 | 如何通过部分应用和柯里化让函数具象化?
石川
你好,我是石川。
在前面两节课里,我说过函数式编程的核心就是把数据作为输入,通过算法进行计算,最后输出结果。同时我也提到,在函数式 + 响应式编程中,面对未知、动态和不可控时,可以通过纯函数和不可变等手段减少副作用、增加确定性,及时地适应和调整。
那么现在你来想想,在输入、计算和输出这个过程中,什么地方是最难控制的呢?对,就是输入。因为它来自外界,而计算是在相对封闭的环境中,至于输出只是一个结果。
所以今天这节课,我们就来说说输入的控制。
部分应用和柯里化
在前面课程里也讲过,函数的输入来自参数,其中包括了函数定义时的形参和实际执行时的实参。另外,我们也通过 React.js 中的 props 和 state 以及 JavaScript 中的对象和闭包,具体了解了如何通过不可变,做到对运行时的未知状态变化的管理。
那今天,我们就从另外一个角度理解下对编程时“未知”的处理,即如果我们在编写一个函数时,需要传入多个实参,其中一部分实参是先明确的,另一部分是后明确的,那么该如何处理呢?
其实就是部分应用(partial application)和柯里化(currying)。下面我们就一起来看看函数式编程中,如何突破在调用点(call-site)传参的限制,做到部分传参和后续执行。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
本文介绍了函数式编程中的参数处理工具,重点介绍了部分应用和柯里化的概念及应用。部分应用通过提前预置已知参数,减少后续需要传入的参数数量,增加代码的可读性。柯里化则是每次只传入一个参数,通过闭包和延展操作符实现。此外,还介绍了一元参数的改造接口unary,将一个接收多个参数的函数变成只接收一个参数的函数。通过这些技术,函数式编程可以更好地处理未知,提高代码可读性,减少参数数量,体现了函数式底层的声明式思想。文章还介绍了一些常用的工具函数,如constant和identity,以及对参数进行重新排序的方式。总的来说,本文深入浅出地介绍了函数式编程中的参数处理工具,为读者提供了深入理解和应用的指导。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《JavaScript 进阶实战课》,新⼈⾸单¥59
《JavaScript 进阶实战课》,新⼈⾸单¥59
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(13)
- 最新
- 精选
- lugusliu柯里化每次传一个参数这样写是不是更简洁 function partial(fn){ let receivedArgs = [] return function recursionFn(args){ receivedArgs = receivedArgs.concat([...arguments]) if(receivedArgs.length >= fn.length){ return fn(...receivedArgs) }else{ return recursionFn } } }
作者回复: 很简洁👍
2022-11-16归属地:北京4 - Lfunction getCurrentOrder(cb) { getCurrentOrder( { order: CURRENT_ORDER_ID }, cb ); (fetchOrder) } 可是如果我们想进一步具象化,预制一些参数怎么办?比如下面的 getCurrentOrder,如果我们想把前面 getOrder (fetchOrder) 里的 data,也内置成 order: CURRENT_ORDER_ID,这样会大量增加代码结构的复杂性。 这两个地方是不是错了 应该都是fetchOrder
作者回复: 是的,谢谢你的细心,这里有个勘误,getOrder应该都统一成fetchOrder。
2022-09-28归属地:北京3 - Lvar curriedOrderEvntHandler = curry( orderEventHandler ); var fetchOrder = curriedHttpEvntHandler( "http://some.api/order" ); var getCurrentOrder = getOrder( { order: CURRENT_ORDER_ID } ); getCurrentOrder( function editOrder(order){ /* .. */ } ); 这里是否也有问题 为什么前后的函数对不上呢
作者回复: 是的,谢谢你的细心,这里有个勘误,getOrder应该都统一成fetchOrder。
2022-09-28归属地:北京2 - 行云流水老师,我想了解下,知道这些概念,怎么实际应用呢?毕竟我们也是js进阶实战课程。
作者回复: 柯里化和部分应用最大的应用场景就是当一次只传入一个或部分参数的时候。
2022-11-17归属地:海南1 - Sunny看下这个单词 tenary 是否少了一个 "r",正确的是 ternary?
作者回复: 谢谢指正,我查了一下,你的拼写是正确的
2022-09-29归属地:北京1 - Saulvar curriedOrderEvntHandler = curry( orderEventHandler ); var fetchOrder = curriedHttpEvntHandler( "http://some.api/order" ); var getCurrentOrder = getOrder( { order: CURRENT_ORDER_ID } ); getCurrentOrder( function editOrder(order){ /* .. */ } ); -------------------------------------------------------------------------- 第二行我怎么看不懂
作者回复: 原先的orderEventHandler函数有3个参数,url, data 和 callback。 function orderEventHandler(url,data,callback) {} 第一行把orderEventHandler做了柯里化,之后可以每次只传一个参数。 第二行是在柯里化后的curriedHttpEvntHandler中传入了第一个url实参。
2022-09-27归属地:北京1 - 海是蓝天的倒影要多看几遍才能理解
作者回复: 有些概念确实需要反复思考来理解
2022-12-18归属地:海南 - Geek_fcdf7bfunction constant(v) { return function value(){ return v; }; } 这个函数为啥不直接返回v,而要在里面还要多包一层呢。为啥不是像这样: function constant(v) { return v; }
作者回复: 因为嵌套封装可以减少来自外部值的副作用。
2022-10-16归属地:北京4 - Guitconst currying = (fn) => { const l = fn.length return function curried(...prevArgs) { if (l === prevArgs.length) { return fn(...prevArgs) } return (...nextArg) => curried(...nextArg, ...prevArgs) } }2022-09-29归属地:北京2
- Longvar words = " hello world ".split( /\s|\b/ ); console.log(words.filter( (v) => {return v} )) filter函数里面可以写个函数,是不是可以这样理解,这个函数就是用到了柯里化的概念?2023-07-31归属地:日本
收起评论