什么是函数式编程(代码片段)

liyutian liyutian     2023-01-27     503

关键词:

导读

建议先阅读一下这几篇博客:
函数式编程初探
函数式编程入门教程
图解 Monad

什么是函数式编程

函数式编程中的函数指的并不是编程语言中的函数(或方法),它指的是数学意义上的函数,即映射关系(如:y = f(x)),就是 y 和 x 的对应关系。

数学上对于函数的定义是这样的:“给定一个数集 A,假设其中的元素为 x。现对 A 中的元素 x 施加对应法则 f,记作 f(x),得到另一数集 B。假设 B 中的元素为 y。”

所以当我们在讨论“函数式”时,我们其实是在说“像数学函数那样,接收一个或多个输入,生成一个或多个结果,并且没有副作用(稍后解释)”
技术分享图片

实际上当一个函数无论在何处、何时调用,如果使用相同的输入总能持续地得到相同的结果,我们就可以说他具备了函数式的特征。

需要注意的是,纯函数式编程语言中的变量指的也不是命令式编程语言中的变量(即储存状态的单元),而是代数的变量,表示一个未知的数,或者一个可带入函数的值。
(在代数中对于“数本身是什么”这样的问题并不关心,它关心是各种关系及其性质)

所以函数式编程语言中所说的变量只是一个变量的名称,变量的值是不可变的(immutable),也就是说不允许像命令式编程语言中那样多次给一个变量赋值。
(PS:我们真的需要变量吗?

函数是语言中的变量:

  • 变量的值一旦绑定就不再发生变化
  • 变量中存放的与其说是指,不如说是表达式(惰性求值)

函数式编程语言的特性

在了解了函数编程语言的基本概念之后,我们再来看一下函数式编程语言所具备一些特性,理解这些特性将有助于我们更好的理解“什么是函数式编程”。

一,函数是一等公民

函数是一等公民,它的意思就是函数与其他数据类型一样,可以把它们存在数组里,当做参数传递,赋值给变量,可以在任何地方定义,在函数内或函数外,可以作为函数的参数和返回值,也可以对函数进行组合。

二,高阶函数

在函数式编程中,如果函数能满足下面任一要求就可以被称为高阶函数(higher-order function):

  • 接受至少一个函数作为参数
  • 返回的结果是一个函数

三,柯里化

所谓“柯里化” ,就是把一个多参数的函数 f,转换为单参数函数 g,并且这个函数的返回值也是一个函数。

// 柯里化之前
function add(x, y) 
  return x + y;

add(1, 2) // 3
// 柯里化之后
function addX(y) 
  return function (x) 
    return x + y;
  ;

addX(2)(1) // 3

四,副作用

所谓“副作用”,指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果。
在像 C++ 这样的命令式语言中,函数的意义与数学函数完全不同。例如,假设我们有一个 C++ 函数,它接受一个浮点参数并返回一个浮点结果。从表面上看它可能看起来有点像数学函数意义上的映射实数成实数,但是 C++ 函数可以做的不仅仅是返回一个取决于其参数的数字,它还可以读写其他的全局变量,也可将将输出写入屏幕并接收来自用户的输入。但是,在纯函数式语言中,函数只能读取其参数提供给它的内容,并且它对世界产生影响的唯一方式就是通过它返回的值。

五,纯函数

纯函数编程和函数编程的区别在于:是否允许在函数内部执行一些非函数式的操作,同时这些操作是否会暴露给系统中的其他地方?也就是是否存在副作用。如果不存在副作用,或者说可以不用在意这些副作用,那么就将其称为纯粹的函数式编程。

六、引用透明性

函数无论在何处、何时调用,如果使用相同的输入总能持续地得到相同的结果,就具备了函数式的特征。这种不依赖外部变量或“状态”,只依赖输入的参数的特性就被称为引用透明性(referential transparency)。
“没有可感知的副作用”(比如不改变对调用者可见的变量,进行I/O,不抛出异常等)的这些限制都隐含着引用透明性

五,递归和迭代

对于函数式而言,循环体有一个无法避免的副作用,就是它会修改某些对象的状态,通常这些对象又是和其他部分共享的。而且也因为变量值是不可变的,纯函数编程语言也无法实现循环。
所以纯函数编程语言通常不包含像 while 和 for 这样的迭代构造器,而是采用的无需修改的递归。
下面是一段标准的基于循环的方式来计算阶乘:

static int factorialIterative(int n)
    int r = 1;
    for (int i = 1; i <= n; i++) 
        r *= 1;
    
    return r;

而采用递归形式的方式如下:

static long factorialRecursive(long n)
    return n == 1 ? 1 : n * factorialRecursive(n-1)

扩展阅读
http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html
https://www.zhihu.com/question/28292740
https://blog.csdn.net/qq_31179577/article/details/78745248














函数式编程--为什么要学习函数式编程?(代码片段)

函数式编程(FunctionalProgramming,FP)什么是函数式编程?通过纯函数来实现一些细粒度的函数,然后把这些细粒度的函数组合成功能更强大的函数,这一过程就是函数式编程,经典函数式编程库:lodash函数式编程是编程范式之一,... 查看详情

什么是函数式编程(代码片段)

...式编程其实就是编写非故意副作用的程序。课外知识——什么是函数函数简单的说就是从A(定义域)到B(值域)的一个映射过程。当然具体的函数还有各种限制,具体见链接。所以函数式编程也应该是一个从入参到返回值的黑盒子。... 查看详情

函数式编程基本概念(代码片段)

...想是关注计算机执行的步骤,即一步一步告诉计算机先做什么再做什么声明式编程:声明式编程是以数据结构的形式来表达程序执行的逻辑函数式编程:函数式编程和声明式编程是有所关联的,因为他们思想是一致的:即只关注做... 查看详情

函数式编程简介-附入门方法(代码片段)

WHAT?什么是函数式编程?函数式编程是一种编程范式。编程范式又是什么?编程范式是一种解决问题的思路。我们熟悉的命令式编程把程序看作一系列改变状态的指令;而函数式编程把程序看作一系列数学函数映射的组合。编程... 查看详情

为什么说面向对象编程和函数式编程都有问题(代码片段)

我不理解为什么人们会对面向对象编程和函数式编程做无休无止的争论。就好象这类问题已经超越了人类智力极限,所以你可以几个世纪的这样讨论下去。经过这些年对编程语言的研究,我已经清楚的看到了问题的答案,所以,... 查看详情

php函数式编程(代码片段)

什么是函数式编程与面向对象编程(Object-orientedprogramming)和过程式编程(Proceduralprogramming)并列的编程范式。最主要的特征是,函数是第一等公民。强调将计算过程分解成可复用的函数,典型例子就是map方法和reduce方法组合而... 查看详情

python函数式编程以及高阶函数(代码片段)

文章目录一、什么是函数式编程二、高阶函数的概念1.map和reduce函数2.filter函数3.sorted函数此文章参考廖雪峰大神的官网,地址:函数式编程-廖雪峰的官方网站(liaoxuefeng.com)一、什么是函数式编程首先要知道的是,函数... 查看详情

函数式编程java函数式编程学习(代码片段)

...程-Stream流函数式编程思想概述面向对象思想关注的是用什么对象完成什么事情,而函数式编程思想就类似于数学中的函数,主要关注的是对数据进行了什么操作优点代码简洁,开发快;接近自然语言,易于理... 查看详情

函数式编程java函数式编程学习(代码片段)

...程-Stream流函数式编程思想概述面向对象思想关注的是用什么对象完成什么事情,而函数式编程思想就类似于数学中的函数,主要关注的是对数据进行了什么操作优点代码简洁,开发快;接近自然语言,易于理... 查看详情

前端学习之函数式编程—函数式编程概念+头等函数(代码片段)

什么是函数式编程函数式编程(functionprogrammingFP)FP是编程范式之一,我们常听说的还有,面向过程编程,面向对象编程函数式编程的思维方式把现实世界的事物和事物之间的联系抽象到程序世界(对运算... 查看详情

java8函数式编程实例(代码片段)

什么是函数式编程函数式编程是java8的一大特色,也就是将函数作为一个参数传递给指定方法。别人传的要么是基本数据类型,要么就是地址引用,我们要穿一个“动作”。Stream说到函数式编程,就不得不提及Stream,Stream... 查看详情

编程范式——函数式编程入门(代码片段)

该系列会有3篇文章,分别介绍什么是函数式编程、剖析函数式编程库、以及函数式编程在React中的应用,欢迎关注我的blog命令式编程和声明式编程拿泡茶这个事例进行区分命令式编程和声明式编程命令式编程1.烧开水(为第一人... 查看详情

函数式编程(模块基础)(代码片段)

什么是模块?在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相... 查看详情

《java8实战》读书笔记12:函数式编程(代码片段)

....1实现和维护系统13.1.1共享的可变数据13.1.2声明式编程13.2什么是函数式编程13.2.1函数式Java编程13.2.2引用透明性13.2.3面向对象的编程和函数式编程的对比13.2.4函数式编程实战13.3递归和迭代代码清单13-1迭代式的阶乘计算代码清单13-... 查看详情

“完全”函数式编程(代码片段)

...了面向对象编程,还需要函数式编程吗?函数式编程,有什么妙处?函数式的理念主要是:函数式编程是将程序看成是一系列函数的组合。可以将函数作为变量进行赋值,作为函数参数传入,也可以作为返回值返回,函数无处不... 查看详情

函数式编程(代码片段)

...两段代码有问题吗?通常情况下,代码片段1并不会发生什么问题,我们传入年龄,并且判断是不是大 查看详情

前端学习之函数式编程—柯里化(代码片段)

...念柯里化是为了解决函数中不纯函数或函数硬编码的问题什么是硬编码functiongetAge(age)letmin=18returnage>min 函数式编程是保证相同的调用总能得到相同的结果,但当相同的调用有可能不能得到相同的结果时则称之为硬编码... 查看详情

《java8实战》读书笔记12:函数式编程(代码片段)

....1实现和维护系统13.1.1共享的可变数据13.1.2声明式编程13.2什么是函数式编程13.2.1函数式Java编程13.2.2引用透明性13.2.3面向对象的编程和函数式编程的对比13.2.4函数式编程实战13.3递归和迭代代码清单13-1迭代式的阶乘计算代码清单13-... 查看详情