副标题[/!--empirenews.page--]
本文是一篇手把手的函数式编程入门介绍,借助代码示例讲解细腻。但又不乏洞见,第一节中列举和点评了函数式种种让眼花缭乱的特质,给出了『理解函数式特质的指南针:函数式代码的核心特质就一条, 无副作用 』,相信这个指南针对于有积极学过挖过函数式的同学看来更是有相知恨晚的感觉。
希望看了这篇文章之后,能在学习和使用函数式编程的旅途中不迷路哦,兄die~
PS:本人是在《 Functional Programming, Simplified(Scala edition) 》这本书了解到这篇文章。这本书由浅入深循序渐进地对 FP 做了体系讲解,力荐!
手把手介绍函数式编程:从命令式重构到函数式
有很多函数式编程文章讲解了抽象的函数式技术,也就是组合( composition )、管道( pipelining )、高阶函数( higher order function )。本文希望以另辟蹊径的方式来讲解函数式:首先展示我们平常编写的命令式而非函数式的代码示例,然后将这些示例重构成函数式风格。
本文的第一部分选用了简短的数据转换循环,将它们重构成函数式的 map 和 reduce 。第二部分则对更长的循环代码,将它们分解成多个单元,然后重构各个单元成函数式的。第三部分选用的是有一系列连续的数据转换循环代码,将其拆解成为一个函数式管道( functional pipeline )。
示例代码用的是 Python 语言,因为多数人都觉得 Python 易于阅读。示例代码避免使用 Python 范的( pythonic )代码,以便展示出各个语言通用的函数式技术: map 、 reduce 和管道。所有示例都用的是 Python 2 。
- 理解函数式特质的指南针
- 不要迭代列表,使用
map 和 reduce
- 声明方式编写代码,而非命令式
- 现在开始我们可以做什么?
理解函数式特质的指南针
当人们谈论函数式编程时,提到了多到令人迷路的『函数式』特质( characteristics ):
- 人们会提到不可变数据(
immutable data )、一等公民的函数( first class function )和尾调用优化( tail call optimisation )。这些是 有助于函数式编程的语言特性 。
- 人们也会提到
map 、 reduce 、管道、递归( recursing )、柯里化( currying )以及高阶函数的使用。这些是 用于编写函数式代码的编程技术 。
- 人们还会提到并行化(
parallelization )、惰性求值( lazy evaluation )和确定性( determinism )。这些是 函数式程序的优点 。
无视这一切。函数式代码的核心特质就一条: 无副作用 ( side effect )。即代码逻辑不依赖于当前函数之外的数据,并且也不会更改当前函数之外的数据。所有其他的『函数式』特质都可以从这一条派生出来。在你学习过程中,请以此作为指南针。不要再迷路哦,兄die~
这是一个非函数式的函数:
- a = 0
- def increment():
- global a
- a += 1
而这是一个函数式的函数:
- def increment(a):
- return a + 1
不要迭代列表,使用 map 和 reduce
map
map 输入一个函数和一个集合,创建一个新的空集合,在原来集合的每个元素上运行该函数,并将各个返回值插入到新集合中,然后返回新的集合。
这是一个简单的 map ,它接受一个名字列表并返回这些名字的长度列表:
- name_lengths = map(len, ["Mary", "Isla", "Sam"])
- print name_lengths
- # => [4, 4, 3]
这是一个 map ,对传递的集合中的每个数字进行平方:
- squares = map(lambda x: x * x, [0, 1, 2, 3, 4])
-
- print squares
- # => [0, 1, 4, 9, 16]
这个 map 没有输入命名函数,而是一个匿名的内联函数,用 lambda 关键字来定义。 lambda 的参数定义在冒号的左侧。函数体定义在冒号的右侧。(隐式)返回的是函数体的运行结果。
下面的非函数式代码输入一个真实名字的列表,替换成随机分配的代号。
- import random
-
- names = ['Mary', 'Isla', 'Sam']
- code_names = ['Mr. Pink', 'Mr. Orange', 'Mr. Blonde']
-
- for i in range(len(names)):
- names[i] = random.choice(code_names)
-
- print names
- # => ['Mr. Blonde', 'Mr. Blonde', 'Mr. Blonde']
(如你所见,这个算法可能会为多个秘密特工分配相同的秘密代号,希望这不会因此导致混淆了秘密任务。)
(编辑:鞍山站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|