编程范式
编程语言
为什么需要编程语言
机器语言
汇编语言
汇编语言就是将以前机器语言的命令,用一些简单的英文单词来表示,这样不仅很直观,对编程人员的要求也大大降低了。
高级语言
C/C++
C:“中级语言”过程式语言代表
可对位,字节,地址直接操作
代码和数据分离倡导结构化编程
功能齐全:数据类型和控制逻辑多样化
可移植能力强
C with Classes
继承
权限控制
虚函数
多态
Lisp
LiSp:函数式语言代表
- 与机器无关
- 列表:代码即数据
- 闭包
JavaScript
基于原型和头等函数的多范式语言
- 过程式
- 面向对象
- 函数式
- 响应式*
总结
编程范式
什么是编程范式
程序语言特性
- 是否允许副作用
- 操作的执行顺序
- 代码组织
- 状态管理
- 语法和词法
编程范式
命令式
- 面向过程
- 面向对象
声明式
- 函数式
- 响应式
过程式编程
-
自顶向下
-
结构化编程
JS中的面向过程
//数据
export var car={
meter:100,
speed:10,
};
//算法
export function advanceCar(meter){
while(car<meter){
car.meter+=car.speed;
}
}
面向过程式编程有什么缺点?
- 数据与算法关联弱
- 不利于修改和扩充
- 不利于代码重用
为什么后面会出现面向对象
面向对象编程
- 封装
- 继承
- 多态
- 依赖注入*
封装
**关联数
class Car{
//数据
meter:100,
speed:10
advance(meter){
while(this.meter<meter){
this.meter+=this.speed;
}
}
getSpec(){
return `meter:${this.meter};speed:${this.speed};`;
}
}
function main(){
var car=new Car();
car.advance(1000);
}
继承
无需重写的情况下进行功能扩充
class FlyCar extends Car{
height=100
fly(height){
while(this.height<height){
this.height+=this.speed
}
}
}
多态
不同的结构可以进行接口的共享,进而达到函数复用
class FlyCar extends Car{
height=100
fly(height){
while(this.height<height){
this.height+=this.speed
}
}
getSpec(){
return $car.getSpec()+`height:${this.height};`;
}
}
function showCarSpec(car){
new Model({
content:car.getSpec(),
}).show();
}
依赖注入
去除代码耦合
五大原则
-
单一职责原则sRP(Single Responsibility Principle)
一个类应该有且只有一个去改变它的理由,这意味着一个类应该只有一项工作。
-
开放封闭原则oCP(Open-Close Principle)
对象或实体应该对扩展开放,对修改封闭。
-
里式替换原则LSP(the Liskov Substitution Principle LSP)
在对象 x 为类型 T 时 q(x) 成立,那么当 S 是 T 的子类时,对象 y 为类型 S 时 q(y) 也应成立。(即对父类的调用同样适用于子类)
-
依赖倒置原则DIP(the Dependency Inversion Principle DIP)
高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。具体实现应该依赖于抽象,而不是抽象依赖于实现。
-
接口分离原则lsP(the Interface Segregation Principle ISP)
不应强迫客户端实现一个它用不上的接口,或是说客户端不应该被迫依赖它们不使用的方法,使用多个专门的接口比使用单个接口要好的多!
问题
面向对象编程有什么缺点?
面向对象编程语言的问题在于,它总是附带着所有
它需要的隐含环境。你想要一个香蕉,但得到的却
是一个大猩猩拿着香蕉,而且还有整个丛林。
Joe Armstrong(Erlang创始人)
为什么我们推荐函数式编程
函数式编程
- 函数是“第一等公民”
- 纯函数/无副作用
- 高阶函数/闭包
First Class Function
Pure Function
优势
- 可缓存
- 可移植
- 可测试
- 可推理
- 可并行
Currying
Composition
associativity:compose(f,compose(g,h))===compose(compose(f,g).h)
map's composition law:compose(map(f),map(g))===map(compose(f,g));
Functor
可以当做容器的类型,类型支持对容器内元素进行操作
常见的functor:Array(Iterable).map,Promise.then
Monad
可以去除嵌套容器的容器类型
常见monad:Array.flatMap Promise.then
Applicative
直接对两个容器直接操作
Identity:Maybe(id).ap(v)===v:
Homomorphism:Maybe(f).ap(Maybe(x))===Maybe(f(x));
Interchange:v.ap(Maybe(x))===Maybe(f =f(x)).ap(v);
Composition:Maybe(compose).ap(u).ap(v).ap(w)===u.ap(v.ap(w));
响应式编程
异步/离散的函数式编程
- 数据流
- 操作符
-
过滤
-
合并
-
转化
-
高阶
-
Observable
- 观察者模式
- 迭代器模式
- Promise/.EventTarget超集*
操作符
响应式编程的“compose”
- 合并
- 过滤
- 转化
- 异常处理
- 多播
Monad
去除嵌套的Observable
总结
领域特定
语言运行
lexer
- SQL Token分类
- 注释
- 关键字
- 操作符
- 空格
- 字符串
- 变量
Parser语法规则
上下文无关语法规则
推导式:表示非终结符到(非终结符或终结符)的关系。 终结符:构成句子的实际内容。可以简单理解为词法分析中的token。 非终结符:符号或变量的有限集合。它们表示在句子中不同类型的短语或子句。
Parser LL
LL:从左到右检查,从左到右构建语法树
Parser LR
LR:从左到右检查,从右到左构建语法树
LL(K)>LR(1)>LL(1)
tools
exp ::exp'+'exp
exp ::=exp '*' exp
exp ::='NUMBER'
npx kison -m llk -g grammar.js -o cal.js