戳破函数式编程的泡沫

栏目: 编程语言 · 发布时间: 6年前

内容简介:本文是要引入一个框架,从上到下的过程包括

本文是 状态管理框架 选型预研时看到油管上一个Talk的部分内容的总结和一些自己的思考。

要引入一个框架,从上到下的过程包括

  • API的使用 (调用)
  • API的设计 (接口)
  • API的实现 (源码)
  • API实现的是哪个思想 (原理)

状态管理框架 可追根溯源到函数式的本质特性上,所以有必要先搞清楚函数式为何物。

而一个“新”事物的流行往往会产生泡沫,所以总 是会把函数式当成 银弹 ,如同对待 区块链人工智能大数据 一样。在这里希望一方面把函数式的来龙去脉说清,另一方面戳破这些浮夸的 泡沫效应 ,让它回归到原有的价值。

函数式从何而来

函数式的历史可以追述到1930年代的{lambda calculus},函数式编程本质上就是对 λ演算 的一种实现。基本思想就是 只通过“变量”和“函数”两个元素来解决问题 。这个思想给函数式编程带来诸如 匿名函数一等公民柯里化 等概念。

我们所接触到的主流编程语言几乎都是 图灵机 的思想延续,可见这一分支一直是处于绝对统治地位。但随着现代语言越来越多的加入 λ演算 的特性,这两个思想最终产生了交集。

那么函数式思想为什么从一个小众的事物慢慢变成了显学了呢?那么我们看一下这个思想到底给软件工程注入了哪些新鲜血液。

图灵系语言的问题

有一种误解是学习函数式 要忘记掉你所学过的编程方式 ,但与其说引入函数式就是要用它 替代 面向对象 ,还不如说是对 面向对象 的程序进行 重构 ,毕竟两者各有优劣。

我们一开始满足某个业务写的 面向对象 代码可能是以下的样子,你可以把他看做一些页面,函数或是模块。

戳破函数式编程的泡沫

随时业务的变化,可能有些组件被删掉,或是新增了新的模块,也可能是模块间的调用/依赖关系有了变化。于是复杂度开始增大。

戳破函数式编程的泡沫

代码变成这个样子后,虽然表面上仍然可以使用,但是源码却已经 难以理解和维护 我们会发现难以理解的一个原因是: 这个系统一件事的成立,需要大量的前提! ++因为依赖太多++

图灵系的语言也有一样的困境,随着语言的迭代更新,逐渐加入了更多的限制:

  • 比如 Ruby 用{protected method}表示一种函数让其只能被自己和子类所访问
  • C++ 引入{friend function}来表示一个函数不是类的成员函数但是能访问类的私有成员

当一个概念越来越 难以理解 的时候,就到了一个改变的节点上。比如减少概念:Swift就没有protect关键字 [why];但更有效的思路是引入更加 简单函数式

函数式的函数

数学家,和 程序员 一样,对概念的_封装_,_组合_有着巨大的需求。 例如英国数学家在一本著作中花了 379页 推导出 1+1=2

戳破函数式编程的泡沫
戳破函数式编程的泡沫
戳破函数式编程的泡沫

他们是怎么管理好这么多封装,最终能串联起来解决问题的呢? 可否把他们的经验拿来借鉴?

答案就是 数学函数

戳破函数式编程的泡沫

数学函数输入集合到输出集合映射

戳破函数式编程的泡沫

而函数式语言的函数特性就是 数学函数

这和 面向对象 的函数可不一样,我们一般而言的 函数/方法 ,都是一些statement的集合。也就是说,他可以对外界环境进行改造 (比如网络请求,数据库请求),也可以完全没有输入和输出,更不用提说什么映射了。

戳破函数式编程的泡沫

重构1:加入纯函数

但其实要想借鉴过来也很简单,比如大多现代语言都引入了 闭包一等公民 ,在此基础上只需要给日常所写的函数加一个 约束 ,就可以做到类似数学函数的效果。(加了这些约束的函数被称为 纯函数 ,或 引用透明 )这个约束就是: 没有副作用 (只能加工参数,输出结果,不能修改外界环境)

如果我们平时多写纯函数,问题就已经得到了一定的简化。

重构2:加入不可变特性 Immutable

纯函数 带来的一个好处就是 不可变 immutability ,因为 纯函数 只能处理输入,返回输出,那外界的状态就可以通过 拷贝 的方式传递进来,不用修改原来的值:

比如对于把x这个集合传入各种各样的函数内,x并不会改变。

戳破函数式编程的泡沫

这个好处不言而喻,不可变意味着线程安全,意味着不必因为一些bug去查看每一个可能产生的函数。

例如Swift就引入了这个特性,除了 class 都是 值类型 ,传递即拷贝,并通过 copy-on-write 实现按需拷贝,降低空间开销。

重构3:控制副作用

纯函数 不是一个褒义词,如同 副作用 不是一个贬义词一样。

我们程序员获得薪水的原因就是 编写程序通过写一些不纯函数来产生副作用 (例如改变数据库里的数据)

用户不关心代码,只关心你能带给他们什么样的 副作用 ,只有程序员才关心这个过程够不够优雅。

问题在于如何处理 副作用

答案是 ,换句话说就是一层封装,把真正要产生的 副作用 藏起来。调用 只能通过一个 如何修改该值 的函数给它,由这层封装来帮你实现 副作用

如果是状态修改,有一种方式是:当有冲突发生的时候,会重新执行需要再次更新的函数。(类似数据库的transaction)

戳破函数式编程的泡沫

如果是修改外部环境,一般会把请求放到队列里,统一派发。

戳破函数式编程的泡沫

即使是函数式语言, 副作用 也是要做的,不然这个程序就毫无意义,只是我们把 副作用纯函数 隔离了起来,让他们的影响在一个可控的范围内。

这种隐藏状态,通过传递函数修改状态的管理 副作用 的方式,就是我们下面要聊的状态管理思想。

总结,函数式带来的最大好处?

那就是并发!

共享全局状态是维护的噩梦,单纯的乱代码还不足以造成无法理解,可以通过清理最终理清,但如果是并发问题的代码,需要釜底抽薪的改造才可能把各种线程间的协作交接清楚。

即使我们不引入 状态管理框架 ,仅仅是让数组不可变,用Promise/RxSwift之类把异步的代码梳理好,也 至少 能让出现问题的线程拿到了不同版本的数据,由于数据间的隔离就不会有这边遍历那边修改导致的闪退。

如果在应用了Promise/RxSwift之外,引入了 状态管理框架 ,就意味着有了一个方便的途径,可以直接声明一种安全的共享状态,所有的修改都是统一控制的,不仅仅不会出错,还可以让每次修改都能有序的生效。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

ActionScript 3.0 Cookbook中文版

ActionScript 3.0 Cookbook中文版

Joey Lott、Adobe Dev Library / 陈建勋 / 电子工业 / 2007-11-01 / 78.00元

本书讨论了在Flash Player里执行的ActionScript3.0语言,采用问题—解法—讨论的形式讲解开发过程中常见问题的实际解法,例如:检测用户的 Flash Player 版本或操作系统;格式化日期和货币类型;接受用户输入及操作文字字符串;在运行时绘制各种形状;访问音频和视频;使用 Flash Remoting 进行远程过程调用;加载、发送和检索 XML 数据等。 全书涵盖客户端......一起来看看 《ActionScript 3.0 Cookbook中文版》 这本书的介绍吧!

html转js在线工具
html转js在线工具

html转js在线工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具