函数式编程中有一种模式是通过组合多个函数的功能来实现一个组合函数。一般支持函数式编程的工具库都实现了这种模式,这种模式一般被称作compose与pipe。以函数式著称的Ramda工具库为例。

const R = require('ramda');
function inc (num) {
return ++num;
}
const fun1 = R.compose(Math.abs, inc, Math.pow)
const fun2 = R.pipe(Math.pow, Math.abs, inc)
console.log(fun1(-2, 3)) // 7
console.log(fun2(-2, 3)) // 9

从上面的例子可以看出,假设fgh分别表示三个函数,则compose(f,g,h)返回的函数完成类似(...args) => f(g(h(...args)))的功能。即从右到左组合多个函数,前面函数的返回值作为下一个函数的参数;pipe(f,g,h)返回的函数完成类似(...args) => h(g(f(...args)))的功能,即从左到右组合多个函数,前面函数的返回值作为下一个函数的参数;预计最先执行的函数可以接受任意个参数,后面的函数预计只接受一个参数。把compose放在前面讲是因为其更加体现了数学含义上的从右到左的操作。
redux中即有使compose函数的应用来增强store

import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import DevTools from './containers/DevTools'
import reducer from '../reducers'
const store = createStore(
reducer,
compose(
applyMiddleware(thunk),
DevTools.instrument()
)
)

总的来说,composepipe函数接收函数序列,并返回一个函数,使用数组的reduce方法可以很容易实现这两个函数,下面是redux源码中对compose方法的实现:

function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
} if (funcs.length === 1) {
return funcs[0]
} return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

上面的代码是ES6+的实现方式,仿照上面的代码很容易写出ES5的实现方法

function _compose(f, g) {
return function() {
return f.call(this, g.apply(this, arguments));
};
} function compose() {
var args = Array.prototype.slice.call(arguments)
if (args.length === 0) {
return function(arg){
return arg
}
}
if (args.length === 1) {
return args[0]
}
return args.reduce(_compose)
}

实现了compose方法,只需要改动很少的地方就能实现pipe方法。

function pipe(...funcs) {
if (funcs.length === 0) {
return arg => arg
} if (funcs.length === 1) {
return funcs[0]
} return funcs.reduce((a, b) => (...args) => b(a(...args)))
}

或者直接借助compose方法实现pipe

function pipe(...funcs){
if(funcs.length === 0) {
return arg => arg
}
return compose(...funcs.reverse())
}

组合的概念来自于数学,其有一个重要的特性就是结合律

// 结合律(associativity)
var associative = compose(f, compose(g, h)) == compose(compose(f , g), h); // true

符合结合律意味着不管你是把gh分到一组,还是把fg分到一组都不重要。在实际开发过程中,我们可以尽可能的最小化函数的功能,这也符合单一原则,然后通过结合以及组合来完成较大的功能需求。

函数式编程-compose与pipe的更多相关文章

  1. angular2系列教程(六)两种pipe:函数式编程与面向对象编程

    今天,我们要讲的是angualr2的pipe这个知识点. 例子

  2. [学习笔记]JavaScript之函数式编程

    欢迎指导与讨论:) 前言 函数式编程能使我们的代码结构变得简洁,让代码更接近于自然语言,易于理解. 一.减少不必要的函数嵌套代码 (1)当存在函数嵌套时,若内层函数的参数与外层函数的参数一致时,可以这 ...

  3. (转)现代C++函数式编程

    本文转自:http://geek.csdn.net/news/detail/96636     现代C++函数式编程 C++ 函数式编程 pipeline 开发经验 柯里化 阅读2127    作者简 ...

  4. 翻译连载 | 第 11 章:融会贯通 -《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇

    原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...

  5. 翻译连载 | 附录 A:Transducing(上)-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇

    原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...

  6. 从函数式编程到Ramda函数库(一)

    函数式编程是种编程方式,它将电脑运算视为函数的计算.函数编程语言最重要的基础是λ演算(lambda calculus),而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值).和指令式编程相比, ...

  7. python 函数式编程学习笔记

    函数基础 一个函数就是将一些语句集合在一起的部件,它们能够不止一次地在程序中运行.函数的主要作用: 最大化的代码重用和最小化代码冗余 流程的分解 一般地,函数讲的流程是:告诉你怎样去做某事,而不是让你 ...

  8. 给 JavaScript 开发者讲讲函数式编程

    本文译自:Functional Programming for JavaScript People 和大多数人一样,我在几个月前听到了很多关于函数式编程的东西,不过并没有更深入的了解.于我而言,可能只 ...

  9. JavaScript ES6函数式编程(二):柯里化、偏应用和组合、管道

    上一篇介绍了闭包和高阶函数,这是函数式编程的基础核心.这一篇来看看高阶函数的实战场景. 首先强调两点: 注意闭包的生成位置,清楚作用域链,知道闭包生成后缓存了哪些变量 高阶函数思想:以变量作用域作为根 ...

随机推荐

  1. IDEA升级版本后界面出现变小,字体变细的问题解决

    笔者在今天升级了最新版本的IDEA 2019后发现,该版本的IDEA出现了非常诡异的事情如下图: 升级版本后字体居然发生了变化(通过官方导入的我自己的settings文件)还是出现了问题. 问题解决方 ...

  2. Redis主从配置和哨兵监控配置——服务器端环境搭建

    一:介绍 公司用到的redis框架,主要分为cluster的缓存集群和sentinel中的哨兵主从.这种的选用方式一般需要更具业务场景来做区分,两种框架的配置图为:右图为哨兵主从框架和cliuster ...

  3. echarts 折线拐点收藏

    拐点的样式有:

  4. java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"报错

    出现问题的原因: 内存用户验证时,Spring boot 2.0.1引用的security 依赖是 spring security 5.X版本,此版本需要提供一个PasswordEncorder的实例 ...

  5. Hadoop集群管理

    1.简介 Hadoop是大数据通用处理平台,提供了分布式文件存储以及分布式离线并行计算,由于Hadoop的高拓展性,在使用Hadoop时通常以集群的方式运行,集群中的节点可达上千个,能够处理PB级的数 ...

  6. 20164305 徐广皓 Exp3 免杀原理与实践

    免杀原理及基础问题回答 实验内容 任务一:正确使用msf编码器,msfvenom生成如jar之类的其他文件,veil-evasion,自己利用shellcode编程等免杀工具或技巧 使用msf编码器生 ...

  7. 在线制作微信跳转浏览器下载app/打开指定页面源码

    微信自动跳转外部浏览器下载app/打开指定页面源码 源码说明: 适用安卓和苹果系统,支持任何网页链接.并且无论链接是否已经被微信拦截,均可实现微信内自动跳转浏览器打开. 生成的跳转链接具有极佳的防拦截 ...

  8. GDAL create kml

    新增kml 点 public void WriteKmlPiont() { string driverName = "KML"; //MapInfo File OSGeo.GDAL ...

  9. 多线程/多进程/异步IO

    SOCK_STREAM :TCPSOCK_Dgram :UDP family=AF_INET: 服务器之间的通信AF_INET6: 服务器之间的通信AF_UNIX: Unix不同进程间的通信 永远遵循 ...

  10. EXCEL上传POI

    Java SpringMVC POI上传excel并读取文件内容 2017年11月27日 15:26:56 强人锁男. 阅读数:15329   用的SSM框架,所需要的jar包如图所示:,链接地址:j ...