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 ..
    

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

    - 数据集,对数据的操作和返回值都放在了一起.
    - 没有了循环体,就可以少了些临时用来控制程序执行逻辑的变量, 也少了把数据倒来倒去的控制逻辑
    - **代码变成了在描述你要干什么,而不是怎么干.**
    
  • 相关阅读:
    myaql常用函数
    mysql常用表/视图管理语句
    mysql中select五种子句和统计函数
    mysql里表以及列的增删改查
    mysql列类型
    如何删除openfire for苹果,彻底卸载!
    XMPP 服务器 Openfire 的 Emoji 支持问题(进行部分修改)
    iOS5.1下emoji表情显示方框的解决办法
    iOS 获取字符串中的单个字符
    iOS XMPP之常见错误一:(<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized/></failure>)
  • 原文地址:https://www.cnblogs.com/ukzq/p/13770596.html
Copyright © 2011-2022 走看看