通过对一整段代码分成几个函数,相当于给每一个独立的程序逻辑取名字,使得代码变成自解释的。

准则

函数式编程的准则:不依赖于外部的数据,而且也不改变外部数据的值,而是返回一个新的值给你

1
2
3
4
int cnt;
void increment(){
cnt++;
}
1
2
3
int increment(int cnt){
return cnt+1;
}

特性

  • 不可变数据

  • first class functions

  • 尾递归优化

技术

map & reduce

  • 关注要干什么,而不是怎么干
1
2
3
4
5
6
7
8
9
name_len = map(len, ["hao", "chen", "coolshell"])
print name_len
# 输出 [3, 4, 9]
def toUpper(item):
return item.upper()

upper_name = map(toUpper, ["hao", "chen", "coolshell"])
print upper_name
# 输出 ['HAO', 'CHEN', 'COOLSHELL']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
print reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
# 输出 15
# 计算数组中正数的平均值",
num =[2, -5, 9, 7, -2, 5, 3, 1, 0, -3, 8]
positive_num_cnt = 0
positive_num_sum = 0
for i in range(len(num)):
if num[i] > 0:
positive_num_cnt += 1
positive_num_sum += num[i]

if positive_num_cnt > 0:
average = positive_num_sum / positive_num_cnt

print average
# 输出 5
  • 求正数的和(复杂的例子)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 计算数组中正数的平均值",
num =[2, -5, 9, 7, -2, 5, 3, 1, 0, -3, 8]
positive_num_cnt = 0
positive_num_sum = 0
for i in range(len(num)):
if num[i] > 0:
positive_num_cnt += 1
positive_num_sum += num[i]

if positive_num_cnt > 0:
average = positive_num_sum / positive_num_cnt

print average
# 输出 5
1
2
positive_num = filter(lambda x: x>0, num)
average = reduce(lambda x,y: x+y, positive_num) / len( positive_num )

pipeline

只关心输入和输出

recursing

  • currying
1
2
3
4
5
6
7
8
9
10
def inc(x):
def incx(y):
return x+y
return incx

inc2 = inc(2)
inc5 = inc(5)

print inc2(5) # 输出 7
print inc5(5) # 输出 10

higher order function

消除共享变量和状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from random import random
def move_cars():
for i, _ in enumerate(car_positions):
if random() > 0.3:
car_positions[i] += 1
def draw_car(car_position):
print '-' * car_position
def run_step_of_race():
global time
time -= 1
move_cars()
def draw():
print ''
for car_position in car_positions:
draw_car(car_position)
time = 5
car_positions = [1, 1, 1]
while time:
run_step_of_race()
draw()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from random import random

def move_cars(car_positions):
return map(lambda x: x + 1 if random() > 0.3 else x,
car_positions)

def output_car(car_position):
return '-' * car_position

def run_step_of_race(state):
return {'time': state['time'] - 1,
'car_positions': move_cars(state['car_positions'])}

def draw(state):
print ''
print '\n'.join(map(output_car, state['car_positions']))

def race(state):
draw(state)
if state['time']:
race(run_step_of_race(state))

race({'time': 5,
'car_positions': [1, 1, 1]})

pipeline

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 num

nums = [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
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 num
def multiply_by_three(nums):
for num in nums:
yield num * 3
def convert_to_string(nums):
for num in nums:
yield 'The Number: %s' % num

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
# 输出:
# The Number: 6
# The Number: 12
# The Number: 18
# The Number: 24
# The Number: 30

使用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
4
5
6
7
pipeline_func(nums, [even_filter,
multiply_by_three,
convert_to_string])
def pipeline_func(data, fns):
return reduce(lambda a, x: x(a),
fns,
data)

Shell风格函数写作方法

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()

@Pipe
def even_filter(num):
return num if num % 2 == 0 else None

@Pipe
def multiply_by_three(num):
return num*3

@Pipe
def convert_to_string(num):
return 'The Number: %s' % num

@Pipe
def echo(item):
print item
return item

def force(sqs):
for item in sqs: pass

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

force(nums | even_filter | multiply_by_three | convert_to_string | echo)

原文:https://coolshell.cn/articles/10822.html