js函数式编程术语总结 - 持续更新
函数式编程术语
高阶函数 Higher-Order Functions
- 以函数为参数的函数
- 返回一个函数的函数
函数的元 Arity
- 比如,一个带有两个参数的函数被称为二元函数
惰性求值 Lazy evaluation
- 是一种按需求值机制,它会延迟对表达式的求值,直到其需要为止
// 设置一个随机数,需要时,才会计算,每次计算都是一个不同的值
const rand = function*() {
while (1 < 2) {
yield Math.random()
}
}
const randIter = rand()
randIter.next() // 每个执行都给出一个随机值,表达式按需求值。
偏函数 Partial Application
- 即【降元】,将一个 n 元函数转换成一个 n - x 元函数
- 或者这样理解,通过对【复杂的函数】填充一部分数据来构成一个【简单的函数】
- 柯里化就是通过偏应用函数来实现
function add(a, b,c) {
return a + b+c;
}
//也可以
var addOne = add.bind(null, 1,2);
console.log(addOne(2));
//也可以
var addTwo = add.bind(null, 1);
console.log(addTwo(3,4));
柯里化 Currying
- 将一个多参数函数转换成多个单参数函数
- 也就是将一个 n 元函数转换成 n 个一元函数
const sum = (a, b) => a + b
const curriedSum = (a) => (b) => a + b
curriedSum(40)(2) // 42.
const add2 = curriedSum(2) // (b) => 2 + b
add2(10) // 12
自动柯里化 Auto Currying
- 将多个参数的函数转换为单参数的函数
- 如果,给定的参数数量少于正确的参数,则返回一个函数,该函数将获得其余的参数
- 如果,函数得到正确数量的参数时,它就会被求值
- 示例,lodash 和 Ramda 都有一个 curry 函数,但 underscore 没有
const add = (x, y) => x + y
const curriedAdd = _.curry(add)
curriedAdd(1, 2) // 3
curriedAdd(1) // (y) => 1 + y
curriedAdd(1)(2) // 3
compose 组合函数
- 概念:它将需要嵌套执行的函数平铺。嵌套执行指的是,一个函数的返回值将作为另一个函数的参数
- 作用:实现函数式编程中的 pointfree 风格(无参数),使我们专注于【转换】而不是【数据】
- 实现:接收多个函数作为参数,从右到左,一个函数的输入为另一个函数的输出
- 意义:编程更精练、算法更清晰、无参数干扰
- 威力:【任意组合】
- 缺点:不能直观的看到参数
- 示例
var compose = function(fun1,fun2){
return function(val){
return fun1(fun2(val));
}
}
var add = function(val){
return val + "111";
}
var upperCase = function(val){
return val.toUpperCase();
}
var double = function(val){
return val += val;
}
// 无限组合,才是compose的威力所在
var upperCaseThenAdd = compose(add,upperCase);
var doubleThenAdd = compose(double,add);
var addThenAdd = compose(add,add);
var addThenAddThenUpperCase = compose(upperCase,addThenAdd);//注意这个函数,以组合函数addThenAdd作为其参数,很强大,有没有!
console.log(upperCaseThenAdd("china"));//CHINA111
console.log(doubleThenAdd("china"));//china111china111
console.log(addThenAdd("china"));//china111111
console.log(addThenAddThenUpperCase("china"));//CHINA111111
//改进compose,支持2个以上参数
var compose1 = function(){
var args = arguments;
return function(initVal){
var val = initVal;
for(key in args){
val = args[key](val);
}
return val;
}
}
var doubleThenUpperCaseThenAddThenAdd = compose1(double,upperCase,add,add);
console.log(doubleThenUpperCaseThenAddThenAdd("china"));//CHINACHINA111111
Continuation
- 概念:在一个程序执行的任意时刻,尚未执行的代码称为 Continuation
- 作用:异步请求回调、异步监听回调等
- 示例
//continueFun函数就称为一个Continuation
var addOneAndContinue = function(val,continueFun){
var val = val + 1;
return continueFun(val);
}
var mutiply = function(val){
return val * 5;
}
console.log(addOneAndContinue(100,mutiply));//505
纯函数 Purity
- 输出仅由输入决定,不依赖也不修改外部状态,即不产生副作用
副作用 Side effects
- 如果函数与外部可变状态进行交互,则它是有副作用的
幂等性 Idempotent
数学中的幂等性
- foo(x) 将产生与 foo(foo(x))、foo(foo(foo(x))) 等相同的输出
- [二元运算],它需要三个元素:二元运算符以及该运算符作用的两个变量。如四则运算的加、减、乘、除均属于二元运算。乘法下唯一两个幂等实数为0和1
- [一元运算],例如 ++ ,正+,负-。比如[高斯符号],它是一个数学符号,形式为方括号[x],表示不大于x的最大整数,高斯符号是幂等的
接口的幂等性
- 对接口而言,幂等性实际上就是接口可重复调用,在调用方多次调用的情况下,接口最终得到的结果是一致的。比如,在App中下订单的时候,点击确认之后,没反应,就又点击了几次。在这种情况下,如果无法保证该接口的幂等性,那么将会出现重复下单问题
- [http方法的幂等],指的是同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也是一样的(注意,只是服务器状态,和服务器返回状态无关)
- 举例
GET /pageX HTTP/1.1是幂等的。连续调用多次,客户端接收到的结果都是一样的:
GET /pageX HTTP/1.1
GET /pageX HTTP/1.1
GET /pageX HTTP/1.1
GET /pageX HTTP/1.1
POST /add_row HTTP/1.1不是幂等的。如果调用多次,就会增加多行记录:
POST /add_row HTTP/1.1
POST /add_row HTTP/1.1 -> Adds a 2nd row
POST /add_row HTTP/1.1 -> Adds a 3rd row
DELETE /idX/delete HTTP/1.1是幂等的,即便是不同请求之间接收到的状态码不一样:
DELETE /idX/delete HTTP/1.1 -> Returns 200 if idX exists
DELETE /idX/delete HTTP/1.1 -> Returns 404 as it just got deleted
DELETE /idX/delete HTTP/1.1 -> Returns 404
程序的幂等性
- 概念:一个函数执行多次皆返回相同的结果
- 作用:一个函数被调用多次时,保证内部状态的一致性
- 对比:和纯函数相比,幂等主要强调多次调用,对内部的状态的影响是一样的(但多次调用返回值可能不同)。而纯函数,主要强调相同的输入,多次调用,输出也相同且无副作用。纯函数一定是幂等的
- 意义:在任何可能的情况下通过幂等的操作限制副作用要比不做限制的更新要好得多。确保操作是幂等的,可避免意外的发生
//虽然是一个面向对象的例子,但是可以说明问题
var Student = function(name,age){
this.name = name;
this.age = age;
};
Student.prototype.delName = function(){
var response = this.name ? this.name + "已被删除":"name不存在";
this.name = null;
return response;
}
//对内部的影响是一样的,但是返回值可以不同
var lilei = new Student("lilei",19);
console.log(lilei.delName());//lilei已被删除
console.log(lilei.delName());//name不存在
console.log(lilei.delName());//name不存在
Point-Free 风格
- 定义函数时,不显式地指出函数所带参数。这种风格通常需要柯里化或者高阶函数。也叫 Tacit programming
断言函数 Predicate
- 根据输入返回 true 或 false。通常用在 Array.prototype.filter 的回调函数中。
const morethenTwo = (a) => a > 2;
;[1, 2, 3, 4].filter(morethenTwo);
契约 Contracts
- 契约保证了函数或者表达式在运行时的行为。当违反契约时,将抛出一个错误
- 比如数据类型检测
const contract = (input) => {
if (typeof input === 'number') return true
throw new Error('Contract Violated: expected int -> int')
}
const addOne = (num) => contract(num) && num + 1
addOne(2)
addOne('hello') // Error
范畴 Category
【不好理解】
- 范畴是指,对象(object)及它们之间的态射(箭头,箭头可以组合)
- 在程序中,数据类型作为对象,函数作为态射
【一个范畴遵从三个原则】
- 必有一个态射(函数),使得 map 一个对象是它自身
- 态射(函数)必是可组合的
- 合成满足结合律。f ? (g ? h) 与 (f ? g) ? h 是等价的
态射 morphism
- 某一范畴中,对象之前的变换关系(一个变形的函数)
函子 functor(范畴学的内容)
- 一个实现 map 函数的对象
- 在 javascript 中一个常见的函子是 Array,因为它遵守因子的两个准则
- 一致性 Preserves identity,即范畴的第一个原则
- 组合性 Composable
- 示例
//一致性
object.map(x => x) ? object
//组合性
var fun1 = function(x){
return x+1;
}
var fun2 = function(x){
return x*x;
}
var res1 = [1,2,3].map(fun1).map(fun2);
var res2 = [1,2,3].map(function(x){
return fun2(fun1(x));
});
console.log(res1,res2);
Pointed Functor
- 一个具有 of 函数的对象,它将 任何 单独的值放入其中
- ES6增加了 Array.of ,使数组成为一个 Pointed Functor
Array.of(1) // [1]
引用透明性 Referential Transparency
- 定义:一个表达式在程序中可以被它等价的值替换,而不影响结果
- 对函数而言:如果函数的返回值只依赖于其输入值,这种特性就称为引用透明性
- 纯函数具有引用透明性
等式推理 Equational Reasoning
- 指当应用程序由表达式组成,并且没有副作用时,关于系统的真值可以从各个部分推导出来
- 纯函数式语言的优点之一是易于进行等式推理,通过引用透明度实现,并且能够在所有上下文中用等号替换equals
不可变性
- 比如es6中的 const 常量设计
匿名函数 Lambda
- 匿名函数往往被视作一个值
- 匿名函数通常作为高阶函数的参数
- 可以把 Lambda 赋值给一个变量
Monad 对象
- 拥有 of 和 chain 函数的对象。chain 很像 map, 除了用来铺平嵌套数据
- 示例,以数组来实现
//of
Array.of(1,2,3);//[ 1, 2, 3 ]
//chain方法的实现
Array.prototype.chain = function (f) {
return this.reduce((acc, it) => acc.concat(f(it)), [])
};
Array.of('cat,dog', 'fish,bird').chain(s => s.split(','));//[ "cat", "dog", "fish", "bird" ]
Comonad 对象
- 拥有 extract 与 extend 函数的对象
自同态 Endomorphism
- 输入输出是相同类型的函数
- 示例:
// uppercase :: String -> String
const uppercase = (str) => str.toUpperCase()
// decrement :: Number -> Number
const decrement = (x) => x - 1
Applicative Functor
- 一个拥有 ap 函数的对象
同构 Isomorphism
- 不用类型对象的变形,保持结构并且不丢失数据
- 例如,一个二维坐标既可以表示为数组 [2, 3],也可以表示为对象 {x: 2, y: 3}
// 提供函数在两种类型间互相转换
const pairToCoords = (pair) => ({x: pair[0], y: pair[1]})
const coordsToPair = (coords) => [coords.x, coords.y]
console.log(pairToCoords([1, 2]));//{ "x": 1, "y": 2 }
console.log(coordsToPair({x: 1, y: 2}));//[ 1, 2 ]
Setoid 对象
- 定义:拥有 equals 函数的对象。equals 可以用来和其它对象比较。
Array.prototype.equals = function (arr) {
const len = this.length
if (len !== arr.length) {
return false
}
for (let i = 0; i < len; i++) {
if (this[i] !== arr[i]) {
return false
}
}
return true
}
;[1, 2].equals([1, 2]) // true
;[1, 2].equals([3, 4]) // false
半群 Semigroup
- 定义:一个拥有 concat 函数的对象。concat 可以连接相同类型的两个对象
- 示例:比如 Array具有concat方法
Foldable 对象
- 定义:一个拥有 reduce 函数的对象,reduce 可以把一种类型的对象转化为另一种类型
- 示例:将一个list转为number
var sum = [1,2,3,4].reduce(function(total,val){
return total += val;
})
console.log(sum);
类型签名 Type Signatures
- 一种注释方式
//通常 js 会在注释中指出参数与返回值的类型
// functionName :: firstArgType -> secondArgType -> returnType
// add :: Number -> Number -> Number
const add = (x) => (y) => x + y
// increment :: Number -> Number
const increment = (x) => x + 1
//如果函数的参数也是函数,那么这个函数需要用括号括起来。
// call :: (a -> b) -> a -> b
const call = (f) => (x) => f(x)
//字符 a, b, c, d 表明参数可以是任意类型。以下版本的 map 的参数 f,把一种类型 a 的数组转化为另一种类型 b 的数组。
// map :: (a -> b) -> [a] -> [b]
const map = (f) => (list) => list.map(f)
代数数据类型 Algebraic data type
- 由其他类型组合在一起的复合类型。两种常见的代数类型是 sum 和 product
联合类型(对象) Union Type
- 定义:连接不同的数据类型
- 示例:add就是一个联合类型对象,因为js天然支持number和sting求和时,进行自动数据类型转换
// add :: (NumOrString, NumOrString) -> NumOrString
const add = (a, b) => a + b
add(1, 2) // Returns number 3
add('Foo', 2) // Returns string "Foo2"
add('Foo', 'Bar') // Returns string "FooBar"
Product type
- 定义:用一种你可能更熟悉的方式把数据类型联合起来
// point :: (Number, Number) -> {x: Number, y: Number}
const point = (x, y) => ({x: x, y: y})
Sum 类型(有时称为联合类型 )
- 是将两种类型的组合合并成另一种类型
- 之所以被称为 sum ,是因为结果类型中可能的值的数量是输入类型的总和
- JavaScript 没有这样的类型,但是我们可以使用 Set 来假装
// 想象一下,在这里我们不能设置只能具有这些值的类型
const bools = new Set([true, false])
const halfTrue = new Set(['half-true'])
// 弱逻辑类型包含 bools 和 halfTrue 值的总和
const weakLogicValues = new Set([...bools, ...halfTrue])
Option | maybe
- Option 是一种sum type ,它有两种情况,Some 或者 None。
- Option 对于组合可能不返回值的函数很有用
- 在其它的一些地方,Option 也称为 Maybe,Some 也称为 Just,None 也称为 Nothing
js函数式编程术语总结 - 持续更新的更多相关文章
- js函数式编程
最近在看朴灵的<深入浅出nodejs>其中讲到函数式编程.理解记录下 高阶函数 比较常见,即将函数作为参数,或是将函数作为返回值得函数. 如ECMAScript5中提供的一些数组方法 fo ...
- js函数式编程——蹦床函数
概述 这是我在学习函数式编程的时候,关于递归,尾递归,相互递归和蹦床函数的一些心得,记下来供以后开发时参考,相信对其他人也有用. 参考资料:JavaScript玩转Clojure大法之 - Tramp ...
- js函数式编程(二)-柯里化
这节开始讲的例子都使用简单的TS来写,尽量做到和es6差别不大,正文如下 我们在编程中必然需要用到一些变量存储数据,供今后其他地方调用.而函数式编程有一个要领就是最好不要依赖外部变量(当然允许通过参数 ...
- js函数式编程(一)-纯函数
我将写的第一个主题是js的函数式编程,这一系列都是mostly adequate guide这本书的读书总结.原书在gitbook上,有中文版.由于原作者性格活泼,书中夹杂很多俚语,并且行文洒脱.中文 ...
- JS函数式编程 - 概念
最近在看Typescript,顺便看了一些函数式编程,然后半个国庆假期就没有了.做个笔记,分几个部分写吧. 最开始接触函数式编程的时候,第一个接触的概念就是高阶函数,和柯里化.咋一看,这不就是长期用来 ...
- JS中的一些函数式编程术语
组合 Composition 组合某种类型(含函数)的两个元素,进而生成一个该类型的新元素: JavaScript 1 2 3 4 5 6 7 let compose = (f ...
- 关于electron中入口文件main.js一些重要参数(持续更新maybe)
const {app, BrowserWindow} = require('electron') const path = require('path') let mainWindow functio ...
- source insight 编程风格(持续更新)
1.字体Source Code Pro 出身于豪门Adobe,从名字上来看就知道是转为编码而生的.基本上也是拥有前面所提的编程字体的所有要素的.这个字体基本上具有编程字体所需的所有要素:等宽.支持Cl ...
- java编程规范(持续更新)
1:非空判断 错误例子: if(user.getUserName().equals("hollis")){ } 这段代码极有可能在实际运行的时候跑出NullPointerExcep ...
随机推荐
- ASP.NET Core在CentOS上的最小化部署实践
引言 本文从Linux小白的视角, 在CentOS 7.x服务器上搭建一个Nginx-Powered AspNet Core Web准生产应用. 在开始之前,我们还是重温一下部署原理,正 ...
- openJDK知识整理及概念
上周同事去听了阿里openJDK的讲座,收集整理了一下.随着Oracle 撒手,Java 8 官方支持时间持续到 2020 年 12 月:对商业用户(Commercial Users),2019 年 ...
- 《k8s-1.13版本源码分析》- Scheduler启动前逻辑
本文原始地址(gitbook格式):https://farmer-hutao.github.io/k8s-source-code-analysis/core/scheduler/before-sche ...
- C# 替换Word文本—— 用文档、图片、表格替换文本
编辑文档时,对一些需要修改的字符或段落可以通过查找替换的方式,快速地更改.在C# 在word中查找及替换文本一文中,主要介绍了在Word中以文本替换文本的方法,在本篇文章中,将介绍如何用一篇Word文 ...
- 01 Java jdk环境配置
1.1 书籍(B) [1] java核心技术 [2] 实战java 1.2 网址(B) oracle.com http://www.ibm.com/developerWorks/cn/ https:/ ...
- 如何让div中的table水平居中
<div style="text-align:center"> <table border="1" cellpadding="3&q ...
- 关于静态注册BroadcastReceiver接收不到广播的问题
1.背景&解决方法 最近碰到一个需求,app监听特定的广播,接收到广播后启动自己再进行处理.需求很简单,静态注册就好,不过,在自测的时候遇到一个问题,app安装后没启动过的状态下,什么广播都收 ...
- 安卓开发笔记(十三):SQLite数据库储存(下)数据的增添,更改,删除,查询
SQLite数据库存储(下) 1.增添数据 对于添加数据的话我们只需要在主活动当中import新的包以及在主活动当中写上适当的代码就可以了,不需要在我们之前创建新的类当中书写新的代码.现在的主活动 ...
- Ubuntu安装apache+Yii2
1.下载Yii2 https://www.yiichina.com/download 2.将解压后的文件放在指定的位置,这里是/home/www/yii/ 3.安装apache2 sudo apt-g ...
- 不能直接获取?聊聊如何在Shader Graph中获取深度图
0x00 前言 在这篇文章中,我们选择了过去几周Unity官方社区交流群以及UUG社区群中比较有代表性的几个问题,总结在这里和大家进行分享.主要涵盖了** StreamingAssets.Profil ...