您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

沉迷面向对象编程不可自拔?函数式编程了解一下

时间:2020-11-05 12:31:32  来源:  作者:

函数式编程已经存在了60多年,但是到目前为止,它一直都很小众。只有像google这样的改变游戏规则的企业才会依赖函数式编程,普通程序员对此几乎一无所知。

致开发人员:沉迷面向对象编程不可自拔?函数式编程了解一下

 

这种情况很快就要被改变了。像JAVAPython这样的语言已经开始越来越多地开始采用函数编程,但是像Haskell这样的新语言已经完全融入了函数式编程。

简单来说,函数式编程就是为不可变变量构建函数。相反,面向对象的编程是要具有一组相对固定的函数,而我们主要是在修改或添加新变量。

函数式编程具有非常适合诸如数据分析和机器学习之类的需求任务的特性。但是这并不意味着我们应该告别面向对象编程,转而完全使用函数式编程。我们需要了解其中的基本原理,这样我们就能在适当的时候使用它们。

一切都是为了消除副作用

要了解函数式编程,我们需要首先了解函数。 这听起来可能很无聊,但总而言之,它很有见地。

简单地说,函数是将输入转换为输出的东西。只是事情并没有那么简单。思考一下,在Python中的下面这个函数的意义:

def square(x):
    return x*x

这个函数很简单。 它需要一个变量x,可能是一个int,或者是一个 float 或 double,然后输出该变量的平方。

再思考一下下面的这个函数:

global_list = []
def Append_to_list(x):
    global_list.append(x)

乍一看,这个函数接受了一个变量 x,无论是哪种类型,由于没有 return 语句,它什么也不返回。事实真的是这样吗?

如果事先没有定义 global_list,那么这个函数就不能工作,它的输出是相同的列表,尽管经过了修改。虽然 global_list 没有声明输入,但当我们使用该函数时,它就会发生变化:

append_to_list(1)
append_to_list(2)
global_list

它返回了 [1,2],而不是空列表。这可能就是问题所在,列表确实是函数的一个输入,虽然我们没有明确说明。

1.不忠于函数

这些隐含的输入,或者其他情况下的输出,有一个官方名称:副作用。虽然我们只列举了一个简单的例子,但在更复杂的程序中,这些可能会让我们面临真正的困难。

大家可以思考一下该如何测试 append_to_list:我们不仅需要阅读第一行并使用任何 x 来测试函数,还需要阅读整个定义,了解其作用,定义 global_list 并以这种方式进行测试。这个例子告诉我们,当你在处理有数千行代码的程序时,简单的东西很快就会变得乏味。

好消息是,有一个简单的解决方法:对函数作为输入的内容诚实。这样更好:

newlist = []
def append_to_list2(x, some_list):
    some_list.append(x)
append_to_list2(1,newlist)
append_to_list2(2,newlist)
newlist

我们并没有作太大的改变,输出结果仍然是 [1,2],其他所有内容也保持不变。

但是,我们已经更改了一件事情:该代码现在没有副作用。

现在,当我们查看函数声明时,能确切知道发生了什么。如果程序运行不正常,我们也可以轻松地单独测试每个功能并查明哪个功能有问题。

2.函数式编程正在编写纯函数

具有明确声明的输入和输出的函数是没有副作用的函数,而没有副作用的函数就是纯函数。

函数编程的一个非常简单的定义是:仅用纯函数编写程序。纯函数永远不会修改变量,只会创建新的变量作为输出。

此外,对于给定输入的纯函数,我们可以得到特定的输出。相反,不纯函数可能依赖于某些全局变量。因此,如果全局变量不同,则相同的输入变量可能导致不同的输出。后者会让调试和代码维护变得更加困难。

这里有一个容易发现副作用的简单规则:由于每个函数必须具有某种输入和输出,因此没有任何输入或输出的函数声明必须是不纯的。如果采用函数式编程,这是你可能想要更改的第一个声明。

函数式编程不仅是 map 和 reduce

循环不是函数式编程中的东西。首先,我们先来思考以下的Python循环:

integers = [1,2,3,4,5,6]
odd_ints = []
squared_odds = []
total = 0
for i in integers:
    if i%2 ==1
        odd_ints.append(i)
for i in odd_ints:
    squared_odds.append(i*i)
for i in squared_odds:
    total += i

相较于我们要执行的简单操作,以上代码明显过长。而且也没有起到作用,因为我们正在修改全局变量。

相反,我们可以用以下代码替代:

from functools import reduce
integers = [1,2,3,4,5,6]
odd_ints = filter(lambda n: n % 2 == 1, integers)
squared_odds = map(lambda n: n * n, odd_ints)
total = reduce(lambda acc, n: acc + n, squared_odds)

这是完整的函数式。它比较短,也更快,因为我们不需要迭代太多的数组元素。如果你理解 filter, map 和 reduce 如何工作,代码也就不难理解了。

这并不意味着所有的函数代码都使用 map、reduce 等。这也不意味着你需要函数式编程来理解 map 和 reduce。只是当你抽象循环时,这些函数会弹出很多。

1.Lambda函数

在谈到函数式编程的历史时,许多人都是从lambda函数的发明开始的。 尽管 lambda 是函数式编程毫无疑问的基石,但它们并不是根本原因。

Lambda 函数是可用于使程序起作用的工具。 但是,我们也可以在面向对象的编程中使用lambda。

2.静态类型

上面的示例虽然不是静态类型的,但是它依然是函数式的。

即使静态类型为我们的代码增加了一层额外的安全保护,但是其函数正常也并非必不可少。 不过,这可能是一个不错的补充。

有些编程语言的函数式编程越来越强

1.Perl

Perl 对副作用的处理方法与大多数编程语言截然不同。它包含了一个神奇的参数 $ 。Perl 确实有它的优点,但我不会用它进行函数式编程。

2.Java

如果你在用 Java 进行函数式编程,那我只能祝你好运了。因为你的程序有一半是由静态关键字组成的,而且其他 Java 开发人员也会把你的程序视为耻辱。

这并不是说 Java 有多糟糕,而是因为它并不是为那些用函数式编程解决问题而设计的,比如数据库管理或机器学习应用程序。

3.Scala

有趣的是:Scala 的目标是统一面向对象和函数式编程。如果你觉得这有点奇怪,那你不是一个人,因为所有人都这么觉得:函数式编程的目标是完全消除副作用,而面向对象编程是把副作用保留在对象内部。

尽管如此,很多开发人员认为 Scala 是一种帮助他们从面向对象编程过渡到函数式编程的语言。或许在未来几年里,它们会更容易全面发挥作用。

4.Python

Python 鼓励函数式编程。一个事实就能看到这一点:每个函数在默认情况下至少有一个输入self。这很像Python的禅:显式比隐式好!

5.Clojure

据它的创建者说,Clojure 大约有 80% 是函数式编程。默认情况下,所有值都是不可变的,就像在函数式编程中需要它们一样。但是,我们可以通过在这些不可变的值周围使用可变值包装器来解决这个问题。当你打开这样一个包装,你得到的东西又是不变的。

6.Haskell

这是为数不多的纯函数式和静态类型的语言之一。虽然在开发过程中这看起来像是一个时间消耗器,但在调试程序时,Haskell会付出巨大的代价。它不像其他语言那么容易学,但绝对值得投资!

 

大数据时代带来了函数式编程

与面向对象编程相比,函数式编程仍然是一个新生儿。但是如果在 Python 和其他语言中包含函数式编程原理,具有不一样的意义,那么函数式编程就有可能获得关注。

函数式编程对于大型数据库、并行编程和机器学习非常有用。在过去的十年里,所有这些都在蓬勃发展。

虽然面向对象代码有着不可估量的优点,但函数代码的优点却不容忽视。只需要学习一些基本原理,就足以让我们成为一名开发人员,并为未来做好准备。

 

--END--

本文作者:Rhea Moutafis,原文链接:https://towardsdatascience.com/why-developers-are-falling-in-love-with-functional-programming-13514df4048e

喜欢本文的同学记得转发+点赞~

更多内容,欢迎大家关注我们的公众号:为AI呐喊(weainahan)



Tags:函数式编程   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
开始切入正题之前,有必要告知大家一下,这篇文章可能有一些深度,初学者可能理解会有些吃力。我会尽量把复杂问题简单化,争取让每个阅读的童鞋们都能看得懂。希望你对element-ui,vu...【详细内容】
2022-03-16  Tags: 函数式编程  点击:(78)  评论:(0)  加入收藏
函数式编程已经存在了60多年,但是到目前为止,它一直都很小众。只有像Google这样的改变游戏规则的企业才会依赖函数式编程,普通程序员对此几乎一无所知。 这种情况很快就要被改...【详细内容】
2020-11-05  Tags: 函数式编程  点击:(126)  评论:(0)  加入收藏
JavaScript是一种发展迅速的语言。这篇文章,我想展示一些有关如何在JavaScript中应用函数式编程的示例。JavaScript中的函数式编程即使函数式编程可以极大地改善应用程序的代...【详细内容】
2020-06-09  Tags: 函数式编程  点击:(57)  评论:(0)  加入收藏
函数式编程或者函数程序设计,又称泛函数编程,是一种编程范式。在Python中,函数编程主要有以下4个函数的使用构成:lambda()、map()、reduce()、filter(),下面我们来一一讲解这些...【详细内容】
2020-04-16  Tags: 函数式编程  点击:(55)  评论:(0)  加入收藏
为什么函数式编程正在上升 编程范例是一个术语,用于描述编写命令的方法。 语言的真正思想是建立在其编程范例之上的。 最著名的三种范例是面向对象的程序设计,命令式程序设计...【详细内容】
2020-03-11  Tags: 函数式编程  点击:(176)  评论:(0)  加入收藏
函数式编程在前端已经成为了一个非常热门的话题。在最近几年里,我们看到非常多的应用程序代码库里大量使用着函数式编程思想。...【详细内容】
2019-09-24  Tags: 函数式编程  点击:(265)  评论:(0)  加入收藏
前置内容为了更容易理解闭包,在说闭包之前,讲一下两个概念:作用域和嵌套函数。 作用域作用域是变量能被访问的范围,定义在函数内的变量是局部变量,局部变量的作用范围只能在函数...【详细内容】
2019-07-17  Tags: 函数式编程  点击:(433)  评论:(0)  加入收藏
▌简易百科推荐
1. 前言了解响应式编程,首先我们需要了解函数式操作和Stream的操作,下面我们简单的复习一下喽。1.1 常用函数式编程函数式接口中我们先来回顾一下Java中的函数式接口。常见的...【详细内容】
2022-07-15  二哥学Java    Tags:编程   点击:(1)  评论:(0)  加入收藏
在本文中,我们将学习如何使用 Next.js、 Prisma、 Postgres 和 Fastify 构建一个 Full-stack 应用程序。在本文中,我们将学习如何使用 Next.js、 Prisma、 Postgres 和 Fastif...【详细内容】
2022-07-12  qaseven    Tags:全栈   点击:(9)  评论:(0)  加入收藏
好的软件开发网站有哪些?做软件开发哪些网站能提供帮助呢?这些很多做软件开发的小伙伴都会问到的问题。007出海全球社交流量导航网站,整合了多方出海跨境网站资源,为你介绍出海...【详细内容】
2022-07-08  Chuhai007    Tags:软件开发   点击:(10)  评论:(0)  加入收藏
我们用monkey做压力测试后,会保存一个monkey日志,那如果想快速的分析日志中有哪些异常,我们可以用批处理工具进行快速的筛查,我们一起来看看吧。先编写个小脚本,然后修改为bat后...【详细内容】
2022-07-08  溪流涌动    Tags:monkey   点击:(13)  评论:(0)  加入收藏
白盒测试落地实践分为两个大方向,一个是静态分析,一个是动态分析,当然啦,也可以叫做静态测试和动态测试。那我们如何高质量保效率的做好白盒测试呢?Parasoft已经为您准备好了成熟...【详细内容】
2022-07-08  Parasoft中国    Tags:白盒测试   点击:(11)  评论:(0)  加入收藏
Altium Designer 自带脚本功能的开发项目,可以调用官方AD API接口对原理图或者PCB进行自动操作,本文主要分享开发的流程,和一些基本的概念信息,本文介绍的脚本工具例子可以用在P...【详细内容】
2022-07-07  电子工程师伟哥    Tags:Altium Designer   点击:(21)  评论:(0)  加入收藏
一、目录介绍 前置知识点 NIO Netty 的核心组件 Channel Callback Future 和 Promise 事件和 ChannelHandler Hello World二、前置知识点1、NIO首先我们需要回顾一...【详细内容】
2022-07-06  架构师jickly    Tags:聊天系统   点击:(16)  评论:(0)  加入收藏
1.事件流事件流是对事件执行过程的描述,了解事件的执行过程有助于加深对事件的理解,提升开发实践中对事件运用的灵活度。2.捕获和冒泡捕获阶段是【从父到子】的传导过程,冒泡阶...【详细内容】
2022-07-06  金乾坤    Tags:API   点击:(13)  评论:(0)  加入收藏
刷盘策略CommitLog的asyncPutMessage方法中可以看到在写入消息之后,调用了submitFlushRequest方法执行刷盘策略:public class CommitLog { public CompletableFuture<PutMe...【详细内容】
2022-07-06  Java码农之路    Tags:RocketMQ   点击:(16)  评论:(0)  加入收藏
最近读了本好书-《深度学习推荐系统》,读完不觉全身通畅,于是就有了写这篇文章的想法,把自己的理解和总结分享给大家。 本文将按照从算法到工程的顺序,先介绍一下推荐系统整体...【详细内容】
2022-07-05  InfoQ    Tags:推荐系统   点击:(22)  评论:(0)  加入收藏
站内最新
站内热门
站内头条