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

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

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

文章插图
 
这种情况很快就要被改变了 。像JAVA或Python这样的语言已经开始越来越多地开始采用函数编程,但是像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 = 0for i in integers:if i%2 ==1odd_ints.append(i)for i in odd_ints:squared_odds.append(i*i)for i in squared_odds:total += i相较于我们要执行的简单操作,以上代码明显过长 。而且也没有起到作用,因为我们正在修改全局变量 。
相反,我们可以用以下代码替代:
from functools import reduceintegers = [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)


推荐阅读