怎么理解函数式编程?


接触这个概念还是在使用了Java的lambda表达式后,话说虽然不应该一直追求什么新概念新技术,但是这确实不是什么新的东西啊,都搞了好多年了,只不过在Java中应用的时间不长罢了,还记得毕业前Java8就出来了,但是后来一直都没怎么用过,现在用的稍稍多了点,所以来看看大概,但是要深入理解也还是懵懂的。

把看到的相关内容集中一下看自己能不能理解的更好一点。就是拷过来的,不是随意转载,文末都有原文链接,所以看时不要说现在各种文章现状:抄来抄去。


相关:

命令式编程:

一般我们实现一个系统有两种思考方式,一种专注于如何实现,比如下厨做菜,通常按照自己熟悉的烹饪方法:首先洗菜, 然后切菜,热油,下菜,然后…… 这看起来像是一系列的命令合集。对于这种”如何做”式的编程风格我们称之为命令式编程, 它的特点非常像工厂的流水线、计算机的指令处理,都是串行化、命令式的。

CookingTask cookingTask = new CookingTask();
cookingTask.wash();
cookingTask.cut();
cookingTask.deepFry();
cookingTask.fried();
...

声明式编程

还有一种方式你关注的是要做什么,我们如果用lambda和函数式来解决上述问题应该是这样的:


public class CookingDemo {
public void doTask(String material, Consumer<String> consumer) {
consumer.accept(material);
}
public static void main(String[] args) {
CookingDemo cookingDemo = new CookingDemo();
cookingDemo.doTask("蔬菜", material -> System.out.println("清洗" + material));
cookingDemo.doTask("蔬菜", material -> System.out.println(material + "切片"));
cookingDemo.doTask("食用油", material -> System.out.println(material + "烧热"));
cookingDemo.doTask("", material -> System.out.println("炒菜"));
}
}

这里我们将烹饪的实现细节交给了函数库,它最大的优势在于你读起来就像是在问题陈述,采用这种方式我们很快可以理解它的功能, 当你在烹饪流程中添加其他步骤也变得非常简单,你只需要调用doTask方法将材料传递进去处理,比如在食用油烧热前我要打个鸡蛋:


cookingDemo.doTask("鸡蛋", material -> System.out.println(material + "打碎搅拌均匀"));

而不用再编写一个处理鸡蛋的方法。

函数式编程

使用函数来编程的方式,属于数学category里的一个范畴学,早已有之,只不过恰好应用到了编程来了而已。

其核心是:在思考问题时,使用不可变值和函数,函数对一个值进行处理,映射成另一个值。(注意这里的不可变值,搞懂了外什么在函数式接口中不能改变函数外的变量值了,还一般要求是final的)

函数不能有副作用:我就当做是不影响函数外的任何变量吧,就是函数必须要是在自己的方法里面定义变量来操作或者传一个final的变量进来。但是也不会有绝对的不能影响吧,所有如果对使用者没有太大影响的话就可以的吧。另一个理解就是从范畴学来讲:函数式编程只是范畴论的运算方法,跟数理逻辑、微积分、行列式是同一类东西,都是数学方法。所以函数式编程要求函数必须是纯的,不能有副作用。因为它是一种数学运算,原始目的就是求值,不做其他事情,否则就无法满足函数运算法则了。

在函数式编程中,函数就是一个管道(pipe)。这头进去一个值,那头就会出来一个新的值,没有其他作用。

我们构建函数式的准则是,被称为“函数式”的函数或方法都只能修改局部变量,除此之外,它引用的对象都应该是final的。 所有的引用类型字段都指向不可变对象。

函数式编程的特点是使用表达式来代替语句:"表达式"(expression)是一个单纯的运算过程,总是有返回值;"语句"(statement)是执行某种操作,没有返回值。函数式编程要求,只使用表达式,不使用语句。也就是说,每一步都是单纯的运算,而且都有返回值。

如这样的语句:(1 + 2) * 3 - 4

函数式编程使用:

 subtract(multiply(add(1,2), 3), 4)

或:add(1,2).multiply(3).subtract(4)

函数应该是可以组合的,就是符合结合律:

怎么理解函数式编程?

f(X)=Y

g(Y)=Z

g(f(X))=Z

怎么理解函数式编程?怎么理解函数式编程?


函数就像数据的管道(pipe)。那么,函数合成就是将这些管道连了起来,让数据一口气从多个管道中穿过。

函子:包含了值和变形关系

怎么理解函数式编程?怎么理解函数式编程?

左边的人名圈+函数f就是函子(数据来源)

学习函数式编程,实际上就是学习函子的各种运算。由于可以把运算方法封装在函子里面,所以又衍生出各种不同类型的函子,有多少种运算,就有多少种函子。函数式编程就变成了运用不同的函子,解决实际问题。

比如Java Stream中的各种map、filter等运算,就是学这些东西,这不就是熟悉api嘛,熟悉了之后将其相互各个组合就得出了所需要的结果,但是最开始的数据源不能受影响。


我的总结:

函数式编程主要就是要理解这个函数式是什么意思。

“函数”就按数学里面的函数来理解,比如求正弦的函数sin,或者cos、tan等,或者什么拉格朗日定理下的函数公式那样的东西,就是输入一个值计算出另一个数据来,而程序中的函数大概就是各种包装定义好了的各种方法吧,在这些方法里面定义好计算步骤。

“式”就是方式。

因此“函数式编程”就是指使用调用定义好的方法来计算求值的一种编程方式。这些方法可以在调用的时候自己临时定义或者调用已经写好的方法,如Java lambda表达式中需要自定义的map()或者写好的count()、distinct()等。而且这些函数还是可以连续调用的,因此函数就像是一个个管道,从开始的一端塞进去一些数据,然后让这些数据一个个经过这些定好方法的管道,管道是可以拼接连续的,最后得到所需要的数据。

如果实在是难以理解,那么就记住那些lambda中的各个方法就是函数就可以了。记住这些方法,灵活使用,那么你就比一般人厉害了。最好是不要瞎用或过度使用。


我所学到的任何知识都是来自于其他人的分享。然后加上自己的思考。

参考链接:

http://biezhi.me/2017/07/19/keep-up-with-java8-functional-programming.html

http://www.ruanyifeng.com/blog/2012/04/functional_programming.html

http://www.ruanyifeng.com/blog/2017/02/fp-tutorial.html

https://www.ibm.com/developerworks/cn/java/j-fp/#artrelatedtopics


刚才又看了一篇别人的博客,记一下地址

http://m.blog.****.net/m48o8gewuc/article/details/72871642