编程范式

编程范式,又称为编程模型,泛指软件编程过程中使用的编程风格,常见的编程范式包括命令式编程(面向对象、面向过程等),声明式编程(响应式、函数式),

命令式编程 是面向计算机硬件的抽象,有变量、赋值语句、表达式、控制语句等,可以理解为 命令式编程就是冯诺伊曼的指令序列。 它的主要思想是关注计算机执行的步骤,即一步一步告诉计算机先做什么再做什么。

声明式编程 是以数据结构的形式来表达程序执行的逻辑。声明式编程范式关注的焦点不是采用什么算法或者逻辑来解决问题,而是描述、声明解决的问题是什么。当你的代码匹配预先设定好规则,业务逻辑就会被自动触发执行。SQL、HTML 、XML、 CSS 都属于声明式编程。它的特点:1.它不需要创建变量用来存储数据 2.另一个特点是它不包含循环控制的代码。

如图:

program

函数式编程

函数式编程是面向数学的抽象,将计算描述为一种表达式求值,其实,函数式程序就是一个表达式。函数式编程中函数并部署指计算机中的函数,而是指数学中的函数,即自变量的映射。函数的值取决于函数的参数的值,不依赖于其他状态,比如abs(x)函数计算x的绝对值,只要x不变,无论何时调用、调用次数,最终的值都是一样。

核心理念

  • 函数是第一等公民:函数是第一等公民:是指函数跟其它的数据类型一样处于平等地位,可以赋值给其他变量,可以作为参数传入另一个函数,也可以作为别的函数的返回值。

  • 函数是纯函数:纯函数是指相同的输入总会得到相同的输出,并且不会产生副作用的函数。无副作用 指的是函数内部的操作不会对外部产生影响(如修改全局变量的值、修改 dom 节点等)。

  • 不可变性:没有可变变量、类似代数变量

  • 迭代是通过递归实现的:没有循环结构

优势

  • 确定性:消除了多线程中的数据竞争问题

  • 同一个输入始终产生同一个输出,结果可缓存、结果可测试

  • 只要编译成功,就能成功运行,不受可变性影响

函数合成(compose)

指的是将代表各个动作的多个函数合并成一个函数。

高阶函数

在函数式编程中,函数被称为first class,意思是函数与值一样,可以作为函数参数传入函数,也可以作为函数返回值返回。

高阶函数:将函数作为参数或返回值的函数。

函数复合

在函数式编程中,函数的复合和数学函数复合概念一致,想法是通过组合更小的、更简单的函数构建更大的、更复杂的函数。

嵌套调用与复合运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
toString :: Int -> String
toString n = show n
toArray :: String -> Array String
toArray s = {s}
-- 嵌套调用
intToStringArray :: Int -> Array String
intToStringArray n = toArray(toString n)
-- 等价于左复合
intToStringArray :: Int -> Array String
intToStringArray n = toArray <<< toString
-- 等价于右复合
intToStringArray :: Int -> Array String
intToStringArray n = toString >>> toArray

函数柯里化currying

函数柯里化又称部分求值,指的是将多参数函数转换为单参数函数的特性。一个柯里化的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值

解析

1
2
3
4
5
6
7
8
''' haskell
-- 接受三个INT参数,返回一个INT
f :: Int -> Int -> Int -> Int
-- 等价于, 接受一个INT参数,返回一个函数
f :: Int -> (Int -> Int -> Int)
-- 等价于
f :: Int -> (Int -> (Int -> Int))
'''

例子

1
2
3
4
5
6
7
8
9
10
11
-- add :: Int -> Int -> Int 
-- add x y = x + y
-- 等价于
add :: Int -> (Int -> Int)
add x y = x + y
-- 调用
add 1 2
-- 等价于
(add 1) 2
-- add 1 先返回 函数 Int -> Int ,之后使用参数2调用这个函数
-- 而不是直接传入两个参数

闭包closure

函数与其词法环境的组合就是闭包。

lambda函数

语法

  • lambda 函数的语法只包含一个语句,表现形式如下:
    lambda [arg1 [,arg2,.....argn]]:expression
  • 其中,lambda 是 Python 预留的关键字,[arg…] 和 expression 由用户自定义。
  • 具体介绍如下:
    [arg…] 是参数列表,它的结构与 Python 中函数(function)的参数列表是一样的,如下。
1
2
3
4
5
6
7
a, b
a=1, b=2
*args
**kwargs
a, b=1, *args

......
  • expression 是一个参数表达式,表达式中出现的参数需要在[arg......]中有定义,并且表达式只能是单行的,只能有一个表达式。

lambda 特性

  • lambda 函数是匿名的:所谓匿名函数,通俗地说就是没有名字的函数。lambda函数没有名字。

  • lambda 函数有输入和输出:输入是传入到参数列表argument_list的值,输出是根据表达式expression计算得到的值。

  • lambda 函数拥有自己的命名空间:不能访问自己参数列表之外或全局命名空间里的参数,只能完成非常简单的功能。

常见的lambda函数示例:

1
2
3
4
lambda x, y: x*y			# 函数输入是x和y,输出是它们的积x*y
lambda:None # 函数没有输入参数,输出是None
lambda *args: sum(args) # 输入是任意个数参数,输出是它们的和(隐性要求输入参数必须能进行算术运算)
lambda **kwargs: 1 # 输入是任意键值对参数,输出是1

lambda 常见用法

  1. 将lambda函数赋值给一个变量,通过这个变量间接调用该lambda函数。

    add = lambda x, y: x+y

  2. 将lambda函数赋值给其他函数,从而将其他函数用该lambda函数替换。

  3. 将lambda函数作为参数传递给其他函数。

响应式编程

Wikipedia: 在计算中,响应式编程反应式编程(英语:Reactive programming)是一种面向数据流和变化传播的声明式编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。

响应式编程是基于异步数据流构建构建事务关系编程范式

目的:提高应用程序的性能和可伸缩性,以应对高并发和高负载的场景

实现

观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。

img

Reactor 中大部分实现都是按照上图的逻辑来执行的:

  1. 首先是Subscriber(订阅者)主动订阅 Publisher(发布者),通过调用 Publisher 的 subscribe 方法
  2. Publisher 在向下游发送数据之前,会先调用 Subscriber 的 onSubscribe 方法,传递的参数为 Subscription(订阅媒介)
  3. Subscriber 通过 Subscription#request 来请求数据,或者 Subscription#cancel 来取消数据发布(这就是响应式编程中的背压,订阅者可以控制数据发布)
  4. Subscription 在接收到订阅者的调用后,通过 Subscriber#onNext 向下游订阅者传递数据。
  5. 在数据发布完成后,调用 Subscriber#onComplete 结束本次流,如果数据发布或者处理遇到错误会调用 Subscriber#onError

参考

  1. 什么是「函数式编程」? - 知乎 (zhihu.com)
  2. Python 之 lambda 函数完整详解 & 巧妙运用_lambda函数python-CSDN博客
  3. 从架构师的角度带你把“响应式编程”给一次性搞明白,果然绝绝子-腾讯云开发者社区-腾讯云 (tencent.com)
  4. 响应式编程入门之 Project Reactor - 知乎 (zhihu.com)