什么是函数式编程

导读

建议先阅读一下这几篇博客:

函数式编程初探

函数式编程入门教程

图解 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

原文地址:https://www.cnblogs.com/liyutian/p/10036901.html

时间: 2024-10-09 08:47:49

什么是函数式编程的相关文章

Python学习笔记八:文件操作(续),文件编码与解码,函数,递归,函数式编程介绍,高阶函数

文件操作(续) 获得文件句柄位置,f.tell(),从0开始,按字符数计数 f.read(5),读取5个字符 返回文件句柄到某位置,f.seek(0) 文件在编辑过程中改变编码,f.detech() 获取文件编码,f.encoding() 获取文件在内存中的编号,f.fileno() 获取文件终端类型(tty.打印机等),f.isatty() 获取文件名,f.name() 判断文件句柄是否可移动(tty等不可移动),f.seekable() 判断文件是否可读,f.readable() 判断文件是

PYTHON修饰器的函数式编程

转自:http://coolshell.cn/articles/11265.html Python修饰器的函数式编程 Python的修饰器的英文名叫Decorator,当你看到这个英文名的时候,你可能会把其跟Design Pattern里的Decorator搞混了,其实这是完全不同的两个东西.虽然好像,他们要干的事都很相似--都是想要对一个已有的模块做一些"修饰工作",所谓修饰工作就是想给现有的模块加上一些小装饰(一些小功能,这些小功能可能好多模块都会用到),但又不让这个小装饰(小功能

函数式编程

函数式编程 函数式编程的三大特性: immutable data 不可变数据 first class functions 尾递归优化 函数式编程的准则:不依赖于外部的数据,而且也不改变外部数据的值,而是返回一个新的值给你. 如何变得functional: 1. 没有共享变量 2.通过参数和返回值传递数据 3. 函数里没有临时变量 对现有的代码进行重构(refactoring) 使得代码具有functional programming的优点 lambda a, x: x(a) lambda函数可以

Python学习:映射函数(map)和函数式编程工具(filter和reduce)

在序列中映射函数map map函数会对一个序列对象中的每一个元素应用被传入的函数,并且返回一个包含了所有函数调用结果的一个列表. 例1: def sum(x):     return x + 10 L1 = [1,2,3,4,5,6,7] L = map(sum, L1) #结果为[11, 12, 13, 14, 15, 16, 17] map还有更高级的使用方法,例如提供了序列作为参数,它能够并行返回分别以每个序列中的元素作为函数对应参数得到的结果的列表.如例2所示. 例2: def sum(

javaScript函数式编程-包含闭包、链式优化及柯里化

本文着重介绍个人理解的函数式编程. 函数式编程个人理解为:以函数为主要载体的编程方式. 好处: 语义更加清晰 可复用性高 可维护性好 作用域局限.副作用少 基本函数式编程: //实现数组中每个单词首字母大写 //一般写法 const arr = ['apple','orange','pear']; for(const i in arr) { const c = arr[i][0]; arr[i] = c.toUpperCase() + arr[i].slice(1); //slice()从已有的

javascript - Underscore 与 函数式编程

<Javascript函数式编程 PDF> # csdn下载地址http://download.csdn.net/detail/tssxm/9713727 Underscore # githubhttps://github.com/jashkenas/underscore # 中文官方网站http://www.css88.com/doc/underscore/ # CDN<script src="https://cdn.bootcss.com/underscore.js/1.8

LUA 函数式编程demo

什么是函数式编程 http://www.zhihu.com/topic/19585411/hot 函数式编程的本质函数式编程中的函数这个术语不是指计算机中的函数(实际上是Subroutine),而是指数学中的函数,即自变量的映射.也就是说一个函数的值仅决定于函数参数的值,不依赖其他状态.比如sqrt(x)函数计算x的平方根,只要x不变,不论什么时候调用,调用几次,值都是不变的.在函数式语言中,函数作为一等公民,可以在任何地方定义,在函数内或函数外,可以作为函数的参数和返回值,可以对函数进行组合.

[Java] 函数式编程相关概念 - 笔记1

Java 8 引入了 lambda 表达式,以及函数式编程风格.在了解函数式编程过程中,做了些笔记,摘录于本文. 嵌套函数( Nested Function ) 1. 嵌套函数,是指在另一个函数里面定义的一个函数.外层的函数,这里简称为外层函数. 2. 函数的嵌套可以是多层嵌套.嵌套函数可以看到其全部的外层函数的非局部变量.在实际程序中,嵌套的层数一般很少.下面是一个三层嵌套的例子, innerOfInner 也可以访问在 outer 函数体重定义的变量 x . function outer()

python_way.day7 模块(configparser,xml,shutil,subprocess)、面向对象(上)(创建类,类的构成,函数式编程与面向对象编程的选择,类的继承)

python_way.day7 1.模块 configparser,xml,shutil,subprocess 2.面向对象(上) 创建类,类的构成,函数式编程与面向对象编程的选择,类的继承 1.模块 configparser 用于处理特定格式的文件,其本职上使用open来操作,只能是  [test1] 特定的格式 [test1] k1 = 123 k2 = True [test2] k1 = 123 k2 = v1 文件内容 1.获取 import configparser #打开文件找到文件

为什么函数式编程在Java中很危险?

摘要:函数式编程这个不温不火的语言由来已久.有人说,这一年它会很火,尽管它很难,这也正是你需要学习的理由.那么,为什么函数式编程在Java中很危险呢?也许这个疑问普遍存在于很多程序员的脑中,作者Elliotte对此发表了一些见解,我们一起来看看他是怎么说的. 在我的日常工作中,我身边的开发者大多是毕业于CS编程顶级院校比如MIT.CMU以及Chicago,他们初次涉及的语言是Haskell.Scheme及Lisp.他们认为函数式编程是一种自然的.直观的.美丽的且高效的编程样式.但奇怪的是,我和我