为什么开发人员会爱上函数式编程?

函数式编程(FP)已有60年的历史了,但是直到现在,它的使用范围一直非常狭窄。尽管像Google这样的具有世界变革意义的公司都依赖于核心概念,但普通的现代程序员对这种现象了解甚少。



但这很快就会改变。越来越多的FP概念被集成到JavaPython等语言中。还有像Haskell这样的更现代的语言可以完全发挥作用。简单 地说功能编程







,那么就创建了使用不可变变量的函数。相反,面向对象的编程是在使用相对恒定的一组函数时,程序员主要忙于修改现有变量并创建新变量。



FP本质上适用于解决紧急问题,例如数据分析机器学习这并不意味着您需要告别面向对象的编程,而完全转向功能编程。对于现代程序员来说,了解FP的基本原理非常有用,这将使他能够将这些原理应用到可以很好地为他服务的地方。



函数式编程旨在消除副作用



为了了解函数式编程的原理,您首先需要了解什么是“函数”。它可能看起来很无聊,但是最后,它使您乍看之下看不到什么。因此,让我们谈谈功能。



简单来说,函数是一个实体,该实体将传递给它的某些输入转换为输出数据,并返回到调用位置。是的,事实上,并非所有事物看起来总是那么简单。看一下以下Python函数:



def square(x):
    return x*x


此功能非常简单。它采用一个参数,x参数可能是type int,也可能是typefloatdouble,并返回对该结果进行x平方的结果



这是另一个功能:



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


乍一看,它似乎接受x某种类型并且不返回任何内容,因为其中没有表达式return但是,让我们不要下结论!



如果未事先声明变量,该函数将无法正常工作global_list此功能的结果是存储在中的修改后的列表global_list即使global_list未将其声明为传递给函数输入的值,此变量在调用函数后也会更改。



append_to_list(1)
append_to_list(2)
global_list


在上一个示例中多次调用该函数之后,global_list将不再有一个空列表,而是一个list [1,2]这使我们可以说,列表实际上是提供给函数输入的值,尽管在声明函数时并不能以任何方式固定列表。这可能是一个问题。



声明函数时的不诚实



这些隐式输入或输出值有一个正式名称:副作用。我们在这里使用非常简单的示例,但是在更复杂的程序中,副作用可能导致真正的并发症



考虑一下如何测试该功能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


我们在这段代码中没有做太多改变。结果,in中的函数newlist与之前的in一样global_list,结果变为[1,2],其他所有内容看起来都与以前相同。



但是,我们对该代码进行了重大更改。我们摆脱了副作用。这非常好。



即,现在,在阅读函数声明的第一行之后,我们确切地知道了它使用的输入数据。如此一来,如果程序无法按预期方式运行,则可以轻松测试其包含的每个功能,并找到运行不正常的功能。纯函数更易于维护。



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



声明后可以清楚表明需要采取什么措施以及返回什么的函数是没有副作用的函数。没有副作用的功能是纯功能。



这是函数编程的一个非常简单的定义。这是在编写仅包含纯函数的程序。纯函数永远不会修改传递给它们的数据,它们只会创建新的函数并返回它们。 (请注意,我在上一个示例中作了一点欺骗。它是按照函数式编程的精神编写的,但是在函数中它修改了全局变量列表。但是这里我们仅研究FP的基本原理,这就是我这样做的原因。如果您愿意,可以在这里找到更严格的纯函数示例。)



此外,当使用纯函数时,可以期望它们接收与输入相同的数据,将始终生成相同的输出。不纯函数可能取决于某种全局变量。结果,根据全局变量的值,接收相同输入的它们可能产生不同的结果。这个事实会大大使代码的调试和维护复杂化。



有一个简单的经验法则可以检测副作用。由于在声明纯函数时,必须明确定义它们作为输入和返回所接收的内容,因此不接受或返回任何内容的函数将是不干净的。如果您决定将函数式编程技术合并到项目中,那么您可能要做的第一件事就是检查函数声明。



什么不是函数编程



▍映射和归约功能



循环是与功能编程无关的机制。看一下以下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)


这是功能齐全的代码。更短 它更快,因为您不必迭代许多数组元素。而且,如果你处理的功能filtermap并且reduce,事实证明,这个代码是没有太大的难度比在其中使用循环中的一个理解。



这并不意味着在任何功能代码中都会使用mapreduce以及其他此类功能。但这并不意味着要处理此类功能,您需要了解功能编程。关键是要在摆脱循环时经常使用这些函数。



▍Lambda函数



当人们谈论函数式编程的历史时,他们通常从谈论lambda函数的发明开始。但是,尽管lambda函数无疑是函数式编程的基石,但它们并不是FP的主要原因。



Lambda函数是可用于以函数样式编写程序的工具。但是这些功能也可以在面向对象的编程中使用。



▍静态打字



上面的示例不是静态类型的。但这仍然是一个功能代码示例。



即使静态类型为您的代码增加了一层额外的安全保护,但创建功能代码并不是必需的。但是,它可以很好地补充功能编程风格。



应该注意的是,某些语言比其他语言更容易以功能样式进行编程。



有些语言比其他语言更``实用''



▍Perl



Perl具有处理副作用的方法,这使其与大多数其他语言区分开来。即,它具有“魔术变量” $_,可将副作用带到该语言主要特征之一的水平。Perl有其优点,但是我不会尝试用这种语言进行函数式编程。



▍Java



祝您写功能Java代码好运。不会伤害你的 首先,关键字将占用代码的一半static其次,大多数Java程序员都会将您的代码误解。



这并不意味着Java是一种不好的语言。但这并不是为了解决函数式编程最擅长的问题。例如-用于数据库管理或用于从机器学习领域开发应用程序。



▍斯卡拉



Scala是一种有趣的语言。它的目标是统一功能和面向对象的编程。如果您觉得这很奇怪,请知道您并不孤单。毕竟,函数式编程旨在完全消除副作用。面向对象编程是关于限制对象的副作用。



考虑到这一点,我们可以说许多开发人员将Scala视为一种语言,可以帮助他们从面向对象的编程过渡到函数式编程。使用Scala可以使他们将来更容易过渡到完全功能的编程风格。



▍Python



在Python中鼓励使用函数式编程风格。如果我们考虑到每个函数默认都有至少一个参数-的事实,这可以理解self在许多方面,这是“ Zen Python的精神:“显式优于隐式”。



▍Clojure



据该语言的创建者称,Clojure具有大约80%的功能。默认情况下,所有值都是不可变的。但这正是编写功能代码所需要的。但是,您可以使用可变的容器来解决这个问题,在可变的容器中放置不可变的值。而且,如果您从容器中提取值,则该值将再次变得不可变。



哈斯克尔



它是少数几种功能齐全的静态类型语言之一。尽管在开发过程中使用它似乎需要太长时间才能实现功能机制,但这种努力将在代码调试期间获得很多回报。这种语言不像其他语言那么容易学习,但是学习它绝对是值得的投资。



结果



应当指出,现在仍然是大数据时代的开始。大数据即将到来,而不是一个人,而是与朋友一起进行功能编程。



与面向对象编程相比,函数式编程仍然是一种小众现象。但是,如果我们将FP原理在Python和其他语言中的集成视为一种重要现象,那么我们可以得出结论,函数式编程正变得越来越流行。



这是有道理的,因为在机器学习领域中,函数式编程在与数据库,并行编程中表现得很好。在过去的十年中,所有这些都在上升。



尽管面向对象的代码有无数的好处,但您不应轻视功能代码的好处。如果程序员学习了FP的一些基本原理,那么在大多数情况下,这足以提高其专业水平。这些知识还将帮助他为“功能性未来”做准备。



您对函数式编程感觉如何?






All Articles