函数式编程简介

一、函数式编程特点

  1. function is first class citizens,函数是头等公民,直白的说,函数也能作为参数使用. 最简单的例子就是foreach 、 sort函数
  2. no side affect.  所有的改变都在只在函数内部,不会改变任何东西,高内聚。你知道函数会做且会做什么,除此之外别无他物。举一个最简单反例: 可写的全局变量,一旦声明,很难对其进行约束,需要考虑很多问题(并发写、一致性、最大的问题:定位bug时很难确定是那段代码引起的错误)
  3. Mutations is bad! 所有变量只有一次赋值,函数输出数据都是immutable(隐含的所有输入也都是immutable的),由于所有变量在生成(输出)后,都是immutable,所有的赋值操作都在函数内部。

二、为什么我们要用函数式编程

1、从算法出发思考问题,而不是从数据结构来思考问题。

举一个简单的例子,我们要产生小于10的所有偶数和奇数的数组,如果java写,可能就是这样:

        

import java.util.ArrayList;
import java.util.List;
public class MainJava {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            numbers.add(i);
        }
        List<List<Integer>> numberGroups = segregateNumbers(numbers);
        List<Integer> evenNumbers = numberGroups.get(0);
        List<Integer> oddNumbers = numberGroups.get(1);
        System.out.println(evenNumbers);
        System.out.println(oddNumbers);
    }
    private static List<List<Integer>> segregateNumbers(List<Integer> numbers) {
        List<Integer> evenNumbers = new ArrayList<>();
        List<Integer> oddNumbers = new ArrayList<>();
        for (Integer number : numbers) {
            if (number % 2 == 0)
                evenNumbers.add(number);
            else
                oddNumbers.add(number);
        }
        ArrayList<List<Integer>> result = new ArrayList<>();
        result.add(evenNumbers);
        result.add(oddNumbers);
        return result;
    }
}

        如果用functional programming的 scala来写:

object MainScala extends App {
  val numberGroups = 0 to 10 partition (_ % 2 == 0)
  println(numberGroups._1)
  println(numberGroups._2)
}

  把函数作为参数 & 返回值 (High order functions)

class List[T] { 
    // This Function takes anoter Function called "fn" as a parameter
    // that it's applied to each of the elements within the List
    // and filters them if fn returns false for that element.
    def filter[T](fn: T => Boolean): List[T]
}

def times(time: Int): Int=>Boolean = {
    return v => v % time == 0
}

val list: List[Int] = 0 to 9
val triples: List[Int] = list.filter(times(3))
​

构造复杂的组合函数

//1、读站列表:  
void readSiteList(const char *, siteList, (*)(const char *))
//2、读取数据:
void readSite (const char *, (*)(const Data*))
//3、数据集齐: 
void collect(const Data *,  (*)(list<const Data *>))
//4、算法:  
void algo (list<const Data *>, (*)(const Result *))
//5、网路: 
void send2net(const Result *,  (*)(const Result*))
6、本地写文件. 
void write(const Result*, (*)(const Result*))


main = bind(readSiteList,_1,bind(readSite,_1, bind(collect,_1, bind(algo,_1,bind(send2net,_1,bind(write,_1,null))))))

2、代码查错容易

        当你有一个很复杂的计算过程需要debug的时候,我们都是从最终结果数据开始,如果是面向对象的,你定位到底是哪一步错非常困难,(二分法),因为同一个数据有太多的地方会修改它,发现最终结果不对,可能要把所有流程都进行一遍排查,但是函数式编程就简单多了,你只要定位到出错数据,立刻可以找到出错的子函数(产生这个数据的函数),高效快捷的多。

3、天生支持的并行/异步计算

        并行计算天生不是FP的,但FP天生就是支持并行计算的.为什么呢?因为所有输入数据都是immuatable,没有脏数据的问题,也没有并发写的问题。

        spark / play / Kafka

说个题外话,Kafka,这个项目大家都知道,大数据时代的核心技术,可扩展、高容错的发布-订阅消息系统,它就是用scala开发的,而且是开发者的第一个scala项目,最初就是拿来练手的。

        

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值