Ramda与FP类型结合使用的规范及相关实践疑问
函数式类型与Ramda搭配问题解答
两种写法的通用约定
你给出的两段代码执行结果完全等价,背后遵循的是Fantasy Land Functor 规范:
- 所有符合Functor规范的类型(比如你用到的Either、Task,还有数组、普通对象本质上也符合Functor定义)都必须实现原生的
.map实例方法,也就是你第一种链式调用的写法,是Functor类型的原生能力。 - Ramda的
R.map是多态函数,只要传入的参数符合Fantasy Land Functor规范,它会自动调用对应类型的内置.map方法,所以第二种管道写法和第一种链式写法的执行逻辑没有任何区别。
两种写法的适用场景差异:
- 链式写法适合单条带上下文数据的快速转换,不需要和其他逻辑组合时,写法更直观
- 管道写法适合无点风格的逻辑组合,比如你需要把对Either的转换逻辑和其他普通数据处理逻辑拼接,或者需要把这段转换逻辑复用在其他同类型数据上时,管道写法的灵活性更高
// 链式写法 Right('boo') .map(x => x + '!') .map(x => x.toUpperCase()) // 管道写法,和上面结果完全一致 R.pipe( R.map(x => x + '!'), R.map(x => x.toUpperCase()) )(Right('boo'))
目前社区主流的Fantasy Land实现库(比如purify-ts、folktale)都完全兼容Ramda的多态方法,不需要额外适配,直接替换之前ramda-fantasy的能力即可。
用Monad是否可以替代Ramda
二者是互补关系,完全不存在替代的可能性:
- Ramda内置的
R.map/R.chain/R.ap/R.fold等多态方法,本身就是为操作Fantasy Land的类型类(Functor/Monad/Monoid等)设计的通用工具,不需要你自己重复实现针对这些类型的通用操作逻辑 - Ramda的大量基础纯工具函数(比如
R.prop/R.add/R.filter/R.replace等)可以直接作为参数传给Monad的.map/.chain方法,或者放进管道里组合,大幅减少业务中重复的纯数据转换代码 - Monad负责的是封装带上下文的逻辑(比如Either封装可能出错的逻辑、Task封装异步逻辑),而业务逻辑中大量的纯数据转换操作完全可以复用Ramda的能力,二者搭配反而能最大化函数式编程的优势
内容的提问来源于stack exchange,提问作者remtsoy
相关产品推荐
相关产品推荐

