我们在查阅Ramda的文档时,经常会看到一些“奇怪”的类型签名和用法,例如:(Applicativef,Traversablet)=>(a→fa)→t(fa)→f(ta)或者,某些函数的一些“奇怪”用法://当只传递两个函数时,R.ap也可以用作S组合子//R.ap(R.concat,R.toUpper)('Ramda')//=>'RamdaRAMDA'将Ramda“更深层次”的设计逻辑背后的这些“奇怪”点投射出来。本文将对此进行解释,并讲解其背后的通用函数式编程理论知识。Ramda众所周知的方面Ramda通常被认为是Lodash的另一个“更FP”的替代库。与Lodash相比,Ramda的优势(一)在于完整的currying和datalastdesign编程(pipe)带来的便捷流水线。举个简单的代码对比例子:Ramda:constmyFn=R.pipe(R.fn1,R.fn2('arg1','arg2'),R.fn3('arg3'),R.fn4)Lodash:constmyFn=(x,y)=>{constvar1=_.fn1(x,y)constvar2=_.fn2(var1,'arg1','arg2')constvar3=_.fn3(var2,'arg3')return_.fn4(var3)}Ramdatypesignature在Ramda的API文档中,类型签名的语法有些“奇怪”:add:Number→Number→Number我们结合Ramda的柯里化规则稍微推测一下,就可以将这个转换将函数转换为TypeScript定义:exportfunctionadd(a:number,b:number):number;exportfunctionadd(a:number):(b:number)=>number;OK,那为什么Ramda的文档没有直接用TypeScript表达函数的类型呢?——因为更简洁!Ramda文档中的类型签名使用了Haskell的语法。作为一种纯函数式编程语言,Haskell可以非常简洁地表达柯里化的语义。相比之下,TypeScript的表达方式就比较臃肿了。当然,使用Haskell的类型签名的意义不仅限于此,我们再看看其他“奇怪”的函数类型:ap:[a→b]→[a]→[b]Applyf=>f(a→b)→fa→fb(r→a→b)→(r→a)→(r→b)结合文档中的demo:R.ap([R.multiply(2),R.add(3)],[1,2,3]);//=>[2,4,6,4,5,6]R.ap([R.concat('美味'),R.toUpper],['披萨','沙拉']);//=>["tastypizza","tastysalad","PIZZA","SALAD"]//R.ap也可以用作S组合器//当只传递两个函数时R.ap(R.concat,R.toUpper)('Ramda')//=>'RamdaRAMDA'[a→b]→[a]→[b]很好理解,就是笛卡尔积;(r→a→b)→(r→a)→(r→b)我们也可以这样理解,就是两个函数的串接;Applyf=>f(a→b)→fa→fb有点难懂,语法有点生疏,先翻译成TypeScript语法吧::),嗯,这个类型不能简单翻译成TypeScript,因为:TypeScript不支持“类型构造函数”作为类型参数!例如:typeT
