函数式编程之pipeline——很酷有没有
Pipeline
pipeline 管道借鉴于Unix Shell的管道操作——把若干个命令串起来,前面命令的输出成为后面命令的输入,如此完成一个流式计算。(注:管道绝对是一个伟大的发明,他的设哲学就是KISS – 让每个功能就做一件事,并把这件事做到极致,软件或程序的拼装会变得更为简单和直观。这个设计理念影响非常深远,包括今天的Web Service,云计算,以及大数据的流式计算等等)
比如,我们如下的shell命令:
|
1
|
ps auwwx | awk '{print $2}' | sort -n | xargs echo |
如果我们抽象成函数式的语言,就像下面这样:
|
1
|
xargs( echo, sort(n, awk('print $2', ps(auwwx))) ) |
也可以类似下面这个样子:
|
1
|
pids = for_each(result, [ps_auwwx, awk_p2, sort_n, xargs_echo]) |
好了,让我们来看看函数式编程的Pipeline怎么玩?
我们先来看一个如下的程序,这个程序的process()有三个步骤:
1)找出偶数。
2)乘以3
3)转成字符串返回
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
def process(num): # filter out non-evens if num % 2 != 0: return num = num * 3 num = 'The Number: %s' % num return numnums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]for num in nums: print process(num)# 输出:# None# The Number: 6# None# The Number: 12# None# The Number: 18# None# The Number: 24# None# The Number: 30 |
我们可以看到,输出的并不够完美,另外,代码阅读上如果没有注释,你也会比较晕。下面,我们来看看函数式的pipeline(第一种方式)应该怎么写?
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
def even_filter(nums): for num in nums: if num % 2 == 0: yield numdef multiply_by_three(nums): for num in nums: yield num * 3def convert_to_string(nums): for num in nums: yield 'The Number: %s' % numnums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]pipeline = convert_to_string(multiply_by_three(even_filter(nums)))for num in pipeline: print num# 输出:# The Number: 6# The Number: 12# The Number: 18# The Number: 24# The Number: 30 |
我们动用了Python的关键字 yield,这个关键字主要是返回一个Generator,yield 是一个类似 return 的关键字,只是这个函数返回的是个Generator-生成器。所谓生成器的意思是,yield返回的是一个可迭代的对象,并没有真正的执行函数。也就是说,只有其返回的迭代对象被真正迭代时,yield函数才会正真的运行,运行到yield语句时就会停住,然后等下一次的迭代。(这个是个比较诡异的关键字)这就是lazy evluation。
好了,根据前面的原则——“使用Map & Reduce,不要使用循环”,那我们用比较纯朴的Map & Reduce吧。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
def even_filter(nums): return filter(lambda x: x%2==0, nums)def multiply_by_three(nums): return map(lambda x: x*3, nums)def convert_to_string(nums): return map(lambda x: 'The Number: %s' % x, nums)nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]pipeline = convert_to_string( multiply_by_three( even_filter(nums) ) )for num in pipeline: print num |
但是他们的代码需要嵌套使用函数,这个有点不爽,如果我们能像下面这个样子就好了(第二种方式)。
|
1
2
3
|
pipeline_func(nums, [even_filter, multiply_by_three, convert_to_string]) |
那么,pipeline_func 实现如下:
|
1
2
3
4
|
def pipeline_func(data, fns): return reduce(lambda a, x: x(a), fns, data) |
好了,在读过这么多的程序后,你可以回头看一下这篇文章的开头对函数式编程的描述,可能你就更有感觉了。
最后,我希望这篇浅显易懂的文章能让你感受到函数式编程的思想,就像OO编程,泛型编程,过程式编程一样,我们不用太纠结是不是我们的程序就是OO,就是functional的,我们重要的品味其中的味道。
参考
- Wikipedia: Functional Programming
- truly understanding the difference between procedural and functional
- A practical introduction to functional programming
- What is the difference between procedural programming and functional programming?
- Can someone give me examples of functional programming vs imperative/procedural programming?
- OOP vs Functional Programming vs Procedural
- Python – Functional Programming HOWTO
补充:评论中redraiment的这个评论大家也可以读一读。
感谢谢网友S142857 提供的shell风格的python pipeline:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
class Pipe(object): def __init__(self, func): self.func = func def __ror__(self, other): def generator(): for obj in other: if obj is not None: yield self.func(obj) return generator()@Pipedef even_filter(num): return num if num % 2 == 0 else None@Pipedef multiply_by_three(num): return num*3@Pipedef convert_to_string(num): return 'The Number: %s' % num@Pipedef echo(item): print item return itemdef force(sqs): for item in sqs: passnums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]force(nums | even_filter | multiply_by_three | convert_to_string | echo) |
函数式编程之pipeline——很酷有没有的更多相关文章
- Python函数式编程之map()
Python函数式编程之map() Python中map().filter().reduce()这三个都是应用于序列的内置函数. 格式: map(func, seq1[, seq2,…]) 第一个参数 ...
- python3 第二十一章 - 函数式编程之return函数和闭包
我们来实现一个可变参数的求和.通常情况下,求和的函数是这样定义的: def calc_sum(*args): ax = 0 for n in args: ax = ax + n return ax 但 ...
- python3 第二十章 - 函数式编程之Higher-order function(高阶函数)
什么是高阶函数?把函数作为参数传入或把函数做为结果值返回,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式.函数式编程的特点: 函数本身可以赋值给变量,赋值后变量为函数: 允许将函数本身 ...
- 函数式编程之foldLeftViaFoldRight
问题来自 Scala 函数式编程 一书的习题, 让我很困扰, 感觉函数式编程有点神学的感觉.后面看懂之后, 又觉得函数式编程所提供的高阶抽象是多么的强大. 这个问题让我发呆了好久, 现在把自己形成的想 ...
- Python函数式编程之lambda表达式
一:匿名函数的定义 lambda parameter_list: expression 二:三元表达式 条件为真时返回的结果 if 条件判断 else 条件为假的时候返回的结果 三:map map(f ...
- 函数式编程之-bind函数
Bind函数 Bind函数在函数式编程中是如此重要,以至于函数式编程语言会为bind函数设计语法糖.另一个角度Bind函数非常难以理解,几乎很少有人能通过简单的描述说明白bind函数的由来及原理. 这 ...
- 函数式编程之-F#类型系统
在深入到函数式编程思想之前,了解函数式独有的类型是非常有必要的.函数式类型跟OO语言中的数据结构截然不同,这也导致使用函数式编程语言来解决问题的思路跟OO的思路有明显的区别. 什么是类型?类型在编程语 ...
- 函数式编程之-Partial application
上一篇关于Currying的介绍,我们提到F#是如何做Currying变换的: let addWithThreeParameters x y z = x + y + z let intermediat ...
- 函数式编程之-Currying
这个系列涉及到了F#这门语言,也许有的人觉得这样的语言遥不可及,的确我几乎花了2-3年的时间去了解他:也许有人觉得学习这样的冷门语言没有必要,我也赞同,那么我为什么要花时间去学习呢?作为一门在Tiob ...
随机推荐
- Java 8并行流的性能陷阱
并行化流被分成多个块,每个块独立处理,结果在最后汇总. CPU密集型代码如下: private long countPrimes(int max) { return range(1, max) ...
- bridge和原生交互的简单用法
首先获取当前环境是ios还是Android var u = navigator.userAgent; var isAndroid = u.indexOf('Android') > -1 || u ...
- sync 简单实现 父子组件的双向绑定
这里主要是对vue文档中的sync进行一个再解释: 如果自己尝试的话,最好在已经使用emit 和prop实现了双向绑定的组件中尝试,以免出现不必要的错误: <!DOCTYPE html> ...
- [转帖]LINUX PID 1 和 SYSTEMD
LINUX PID 1 和 SYSTEMD 2017年07月16日 陈皓 评论 46 条评论 57,176 人阅读 https://coolshell.cn/articles/17998.html ...
- Java集合框架(Java总结五)
”https://www.runoob.com/java/” 集合接口区别 List 接口存储一组不唯一,有序(插入顺序)的对象,允许有相同的元素. Set 接口存储一组唯一,无序的对象,不保存重复的 ...
- Linux下signal信号汇总
SIGHUP /* Hangup (POSIX). */ 终止进程 终端线路挂断 SIGINT /* Interrupt (ANSI). */ 终止进程 中断进程 Ctrl+C SIGQUIT /* ...
- 在 Target 中获取项目引用的所有依赖(dll/NuGet/Project)的路径
原文:在 Target 中获取项目引用的所有依赖(dll/NuGet/Project)的路径 在项目编译成 dll 之前,如何分析项目的所有依赖呢?可以在在项目的 Target 中去收集项目的依赖. ...
- string.Compare()方法
判断字符串中是否包含一个值 返回一个值,该值指示指定的 String 对象是否出现在此字符串中. String a = "abcd"; if(source.a("a&qu ...
- The XOR Largest Pair(tire树)
题目 The XOR Largest Pair 解析 一年前听学长讲这道题,什么01trie,好高级啊,所以没学,现在一看.... 看到xor就应该想到二进制,一看数据\(A_i< 2^{31} ...
- ThreadLocal简解
ThreadLocal特点 ThreadLocal实现了线程间数据隔离,ThreadLocal的实例代表了一个线程局部的变量,每条线程都只能看到自己的值,并不会意识到其它的线程中也存在该变量.简单来说 ...