前言

为了清楚起见,请记住,副作用不是必需的坏事,有时副作用是有用的(尤其是在函数式编程范式之外)。

今天聊一聊函数式编程中的隔离思想,它所想隔离的就是“副作用”

我们先从其他角度来聊一聊副作用这个概念。

生活中的副作用

如果我听到副作用这个词后,第一反应是吃药 。

老话说是药三分毒,其中三分毒则为副作用。就比如你感冒了,吃了一些西方某些国家研制的专利药品,然后感冒好了,但是感冒好了之后发现自己秃顶 了。

那么可以说秃顶就是这个感冒药的副作用。

我们来捋一下这个逻辑

感冒好没好?

答:好了这药算不算感冒药 ?

答:算感冒药不吃这个药的话感冒就不会好,吃不吃 ?

答:吃副作用可不可以忍受 ?

答:至少本来就没头发可以忍上面的副作用有些夸大其词了,但是药物一般来说都会有一些副作用。

那么话说回来,程序中呢?

程序的副作用是什么

在I/O模型中,我们希望在在I到O之间只有计算,如果中间包含且不仅包含触发了其他I/O、与此次I -> O计算并不相关的任何事情,都称为副作用。

为什么称之为副作用这样的词语呢,“副作用”这个单词给人第一感觉是糟糕的,从而想让你警惕起来。如果在I/O之间发生了一些我们不知道的副作用,那么我们将无法控制住这个过程,测试过程也会变得非常复杂。

可以想像,如果在I/O之间如果要访问数据库,则必须确保数据库正在运行。如果要写入文件,则必须确保该文件存在并已打开。所以会导致执行过程和测试过程变得很复杂,并不是单一的点对点。

写到这里让我不禁想起了PromiseA+规范的测试用例,官方提供了872种测试用例,你所实现的Promise必须全部通过872种测试用例才符合官方规范。

无副作用的优势

如果一个I/O模型之间没有副作用的话会有什么样的优势呢?我们参照最开始生活角度的那个例子。

如果感冒药换成某东方国家生产的无副作用的药品,在我们感冒的时候,吃感冒药,感冒好了。过程中无任何副作用的产生,不会秃顶。

那么我们就可以放心的在感冒的情况下吃这种药品,而不用考虑其他情况。这就是一个纯的I/O模型。

在编程中,我们声明了一个函数double,如下

在每次输入x = 3的情况下,double返回恒等与6。它不依赖于我们传递它的参数之外的任何东西。

可以想像,在我们调用double的时候,地球上发生着各种各样的事情,如果在调用的瞬间,天上出现了奥特曼,double依然输出6。在固定输入的情况下它是永恒的。

当你写下这个函数之后,你的余生都可以放心使用它,无论上下文如何,它将永久有效。

永恒的东西变化的频率较低,测试起来更加容易,调试起来更加容易。这就是为什么现在很多编程语言都倾向于无副作用。

函数式编程中的副作用概念

如果函数有副作用,我们将其称为过程

函数式编程是基于没有副作用的这样一个简单的前提。在这种范例中,副作用是被排斥的。

如果函数有副作用,我们将其称为过程,或者命令式。因此函数没有副作用。我们认为,如果函数修改了可变数据结构或变量,使用I/O,引发异常或中止错误,则将产生副作用。所有这些东西都被认为是副作用。

副作用之所以不好,是因为(如果有)副作用,取决于系统状态,功能可能是不可预测的。当一个函数没有副作用时,我们可以随时执行它,在给定相同的输入的情况下,它将始终返回相同的结果。

但是要声明一点,函数式编程并不是不需要副作用,只是在需要时限制它们。

需要有副作用,因为没有它们,我们的程序将只能进行计算。

我们经常必须写数据库,与外部系统集成或写文件。与外界通过接口的形式交互才能将我们的计算展示出去。所以很多倾向无副作用的语言的中心细想是把“作用”与“副作用”分离开来处理。

下面我们通过一些特性来看一下。

参照透明

对于同一输入总是返回相同结果的函数称为纯函数。因此,纯函数是没有可观察到的副作用的函数,如果函数有任何副作用,即使我们使用相同的参数调用它,也可能返回不同的结果。所以我们可以将纯函数替换为其计算值,例如:

如果我们输入x = 2, y = 2,那么我们可以得到 4 = sum(2, 2)。

那么sum为纯函数吗?很显然是的,如果我们恒定传入x = 2, y = 2。那么sum将恒定输出4.

那么意味着 f(2, 2) 可以替换为4,比如 Math.floor(sum(2, 2)) 替换之后 Math.floor(4),是一致的。

它就像一个很大的查询表。我们可以这样做是因为它没有任何副作用。用其计算值替换表达式的能力称为参照透明性。

引用透明很重要,因为它允许我们用值替换表达式。此属性使我们能够使用替换模型来思考和推理程序评估。因此,可以说可以用值替换的表达式是确定性的,因为它们始终为给定的输入返回相同的值。

局部副作用

在讲局部副作用之前,我们先来举一个非局部副作用的典型例子。

上述的factorial函数有副作用吗?

答:很显然是有的。函数内部与外界产生了可见的交互,外界result值在函数内部被修改了。而且第一次调用factorial(2) 返回值为 3,第二次调用返回值为6。对于统一输入不能总返回同一结果。这种副作用是被函数式编程思想所排斥的,与外界的交互使得factorial具有不确定性。

接下来我们看一下另一个例子

那么问题来了,这次factorial有副作用吗?

答:有副作用,因为for每次执行的时候都会改变factorial的返回值,result在不断改变。

但是即使这样,factorial(2) 也可以用一个值代替,如果把factorial看作一个黑盒子,从外部我们是看不到副作用的。每次的输入x = 2,总会有固定的返回值3。

换句话说,该函数是具有确定性的,我们说的功能有局部副作用,但此功能的用户并不关心,因为它没有破坏我们的替代模式。因此,即使具有局部副作用,该函数也是纯净的。这也是上面为什么说“产生了可见的交互”,很显然这句话就是这么严谨,如果见不到,依然是纯的。

在函数式编程开发中,可以用一些技巧,比如利用容器,把一些副作用控制在局部以达到纯的目的。

举一些副作用的典型例子

想了想还是在这里立举一些典型有副作用的例子,通过例子可以更好的理解这种思想。

1、与外界交互的。

2、调用I/O的

3、从函数范围之外检索值

4、磁盘检索

5、抛出异常

函数式编程中的副作用概念相关推荐

  1. 函数式编程中的重要概念

    函数式编程中的重要概念 函数式编程范式的意义 函数类型与高阶函数 部分函数 柯里化 闭包 递归 记忆化 原文地址 函数式编程范式的意义 在众多的编程范式中,大多数开发人员比较熟悉的是面向对象编程范式. ...

  2. 函数式编程中的两个棘手问题

    作者 | Matthew Butt­erick 译者 | 弯月 出品 | CSDN(ID:CSDNnews) 大约从十年前,我开始使用Lisp编程语言,后来我喜欢上了函数式编程.每当使用非Lisp语言 ...

  3. 如何在函数式编程中存在时间函数?

    本文翻译自:How can a time function exist in functional programming? I've to admit that I don't know much ...

  4. 函数式编程中的组合子

    函数式编程是一个比较大的话题,里面的知识体系非常的丰富,在这里我并不想讲的特别的详细.为了应对实际中的应用,我们讲一下函数式编程中最为实用的应用方式--组合子.组合子本身是一种高阶函数,他的特点就是将 ...

  5. 函数式编程中的战斗机(二) --运用elm语言MUV设计模式做一个简单的应用实例

    @函数式编程中的战斗机(二) -运用elm语言MUV设计模式做一个简单的应用实例 1 elm语言设计模式的特点 1.1 面向对象设计模式的特点 每种编程语言都有其独特的语法和优缺点,从而导致与众不同的 ...

  6. 简单介绍函数式编程中的Functor(函子),Applicative(加强版函子),Monad(单子)

    原文地址:http://skaka.me/blog/2015/12/19/functor-applicative-monad-scala-haskell/ 如果你是刚接触函数式编程,可能很容易被下面这 ...

  7. socket编程中常见的概念问题!

    socket编程一般指的就是网络编程,常见的服务端和客户机都是必不可少的,今天小千就来给大家介绍一下socket编程中常见的概念问题. 一.常见传输协议 1.tcp协议 TCP (Transmissi ...

  8. Python函数式编程中map()、reduce()和filter()函数的用法

    Python中map().reduce()和filter()三个函数均是应用于序列的内置函数,分别对序列进行遍历.递归计算以及过滤操作.这三个内置函数在实际使用过程中常常和"行内函数&quo ...

  9. 多角度让你彻底明白yield语法糖的用法和原理及在C#函数式编程中的作用

    如果大家读过dapper源码,你会发现这内部有很多方法都用到了yield关键词,那yield到底是用来干嘛的,能不能拿掉,拿掉与不拿掉有多大的差别,首先上一段dapper中精简后的Query方法,先让 ...

最新文章

  1. JQuery+CSS3实现封装弹出登录框效果
  2. 皮一皮:皇上,他在下毒!
  3. 十进制、十六进制、二进制习题
  4. 2015 Multi-University Training Contest 9
  5. C++动态数组简单的模拟二元堆
  6. 如何在Pandas中使用Excel文件
  7. matlab 高级函数
  8. python控制mt4自动交易软件排名_股票自动交易软件排名
  9. 关于雄安新区的一点观察和思考
  10. Github和Git的基本教程,适合新手
  11. 对于注塑模具设计的原则,这些核心你掌握了吗?
  12. 中国无损探伤检测行业发展前景与投资战略规划分析报告2021-2027年
  13. 精选黑科技资源站点,总会有你需要的干货!
  14. 安全合规/法案--31--《数据安全法》原文及解读
  15. Android学习之登陆界面设计(二)基本界面设计
  16. 用宝塔面板网站php变成静态,宝塔面板可以建立静态网站吗?如何部署一个静态页面?...
  17. 计算机网络——基础篇
  18. 这哥们儿的日志让我的心情好得一塌糊涂(ZZ)
  19. VS Code 不止开源
  20. SOUI视频教程 官方论坛

热门文章

  1. ExecuteScaler的三种返回值
  2. wordpress 网站模板-免费wordpress 网站模板以及插件中心
  3. 如此丝滑,Hive 中的各种常用 set 设置用起来就是爽啊
  4. IDS反病毒与APT的具体介绍
  5. HTML中td的colspan和rowspan
  6. 萌新必入!手把手教你玩转Synchronized锁和Lock锁!
  7. IAR一键更新项目文件树及include路径 IAR项目版本降级
  8. conda环境(生信环境搭建)
  9. 数商云采购管理系统:阳光采购,高效降本
  10. Anaconda4.10.3安装