zoukankan      html  css  js  c++  java
  • 函数式编程 1

    小汽车前进的代码
    优化为函数式的写法

    有状态并不是一件很好的事情,无论是对代码重用,还是对代码的并行来说,都是有副作用的.
    因此,想要个方法把这些状态搞掉,于是出现了函数式编程的编程范式.

    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 '
    '.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]})
    

    上面代码呢依然把程序logic分成了函数,不过呢这些函数都是函数式的,它们有三个特点:

    它们之间没有共享的变量;
    函数间通过参数和返回值来传递数据;
    在函数里没有临时变量.
    

    for循环呢也被递归取代了(race函数) -- 递归就是函数式编程中常用到的技术,正如前面所说,递归的本质就是描述问题是什么.

    函数式语言的三套件

    函数式语言有三套件,Map啊,Reduce啊Filter啊,下面看Python的一个示例,这个示例需求为,把一个字符串数组中的字符串都转成小写.
    用常规的面向过程的方式如下:

    # 传统的非函数式
    upname = ['G','CHEN','TANG']
    lowname = []
    for i in range(len(upname)):
          lowname.append( upname[i].lower() )
    

    还真是通俗易懂呢,Python也不过如此
    如果写成函数式,用map()函数,是下面这个样子:

    # 函数式
    def toUpper(item):
          return item.upper()
    
    upper_name = map(toUpper,["r","chen","tang"])
    
    print upper_name
    # 输出 ['R','CHEN','TANG']
    

    其中map函数第一个参数是方法名,第二个参数是方法参数

    上面Python代码呢可以看到,we declare one function method called toUpper,this function has no changed the variables be put in,
    只是把传进来的值做了个simple的operation,然后return,then,we using the toUpper to map function,就可以很清晰地描述出我们想要干什么,
    而不是去理解一个在循环中怎样实现的代码,最终在读了很多循环的逻辑后才发现是什么意思.

    如果你觉得上面的代码在传统的非函数式的方式下还是很容易读的,那么再看一个计算数组平均值的代码:

    # 计算数组中正数的平均值
    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
    

    上面代码如果没注释,你需要看一会儿才能明白,只是计算数组中正数的平均值.

    再看下函数式下使用 filter/reduce 函数的玩法

    # 计算数组中正数的平均值
    positive_num = filter(lambda x: x>0 , num)
    average = reduce(lambda x,y: x+y, positive_num) / len( positive_num )
    

    首先呢,我们使用filter函数把正数过滤出来(注意: lambda x : x>0 这个lambda表达式),
    保存在一个新的数组中 -- positive_num , 然后呢,我们使用reduce函数对数组positive_num求和后,再除以个数,就得到正数的平均值了

    隐藏了数组遍历并且过滤数组控制流程的filter和reduce,不仅让代码更为简洁,因为代码里只有业务逻辑了,而且让我们能更容易地理解代码.

    1. 对num数组filter条件 x > 0 的数据.
    2. 然后对 positive_num 进行 x + y 操作的 reduce , 即求和
    3 ..
    

    感觉代码更亲切了不是吗?

    - 数据集,对数据的操作和返回值都放在了一起.
    - 没有了循环体,就可以少了些临时用来控制程序执行逻辑的变量, 也少了把数据倒来倒去的控制逻辑
    - **代码变成了在描述你要干什么,而不是怎么干.**
    
  • 相关阅读:
    【Hadoop】:HDFS调用Java API进行操作
    aws安装
    神奇的 SQL 之性能优化 → 让 SQL 飞起来
    Hunting and Analyzing High CPU Usage in .NET Applications(实践篇)(转发)
    使用 SOS 对 Linux 中运行的 .NET Core 进行问题诊断(实践篇)(转发)
    good resouces ——开发视频网站推荐(channel9)
    ASP.NET Core 3.1 微软官方教程
    perfview——(教学)
    Dump collection and analysis utility (dotnet-dump)
    Trace for performance analysis utility (dotnet-trace)
  • 原文地址:https://www.cnblogs.com/ukzq/p/13770596.html
Copyright © 2011-2022 走看看