java什么是函数式编程
『壹』 到底什么是函数式编程思维
试着把函数想象成一个根据一个指定输入产出指定输出的黑盒,就能简化成逻辑电路中的各种门的样子或者是各种流通管道的样子。
然后试想数据通过这些组合起来的管道/门,变成你要的结果。
或者是通过现有的管道或门,构建(抽象)出更复杂/更通用的管道/门。
这就是函数式编程。
任何支持函数的语言都可以进行函数式风格的编程 注意到与命令式风格不同的是没有赋值,这意味着reason 程序的时候每个变量的值是不变的 不用考虑程序变量随着时间的变化 -- 大大降低了程序的复杂性。
既然C/C++(98) 也能进行函数式风格的编程 为什么不认为它是一门函数式语言呢,因为需要容易的进行函数式编程需要以下几个语言特性支持
1. closure
按照上面的三条规则函数式是first class 的 是可以直接传递作为参数的,而因为lambda演算作用于是lexical scope 的,variable capture 意味着语言要支持GC才能更方便的操作。 这意味着像Java(8以前), C/C++ 这两门工业界语言函数式编程并不非常适合.
2. 高阶类型推断
因为函数可以作为参数,其类型可以非常复杂 比如下面的函数类型其实非常普遍:
val callCC : (('a -> 'b -> 'c) -> ('a -> 'c) -> 'd) -> ('a -> 'c) -> 'd
如果没有类型推断,其实很难写对或者理解它的语义
3. tail-call
因为函数式风格没有赋值,也就没有for循环, 要实现循环操作 只能通过递归调用, 比如下面简单的例子:
let rec even n = if n = 0 then true else if n = 1 then false else odd (n - 1)
and odd n = if n = 1 then true else if n = 0 then false else even (n - 1)
这需要编译器保证上面的例子不能有stackoverflow 能提供这样保证的编译器并不多,比如所谓的 "函数式" 语言scala 就不能提供这种保证 也就实际上不是函数式语言.
相比函数式风格我觉得更重要的一个语言特性的时代数数据类型和模式匹配
『贰』 什么是函数式编程思维
回答都有跑题,show概念之嫌,题主问的是函数式思维,这个问题我一直在思考,毕竟是方法论,能力有限,只能从切身实践告诉你
1.表达式化
在
最初的时候,需要转变观念,去可变量,去循环,把命令式改成表达式,注意,这只是把你丢在荒山野岭让你感受一下,离开熟悉的环境,地球依然在转,但是有个
重点,那就是一切都是表达式; 为什么是表达式呢?这个问题就像为什么鱼在水里?
因为函数式建立在lambda演算之上而非图灵机,只不过两者被证明等价,所以你可以在你的机器上跑全是表达式的代码,就如有人证明天空适合鱼生存,所以
鱼可以在天上游
当你接受了鱼可以在天上游之后,就该上正餐了
1.5 数据与行为分离
这也是和面向对象不一致的地方,面向对象强调数据与行为绑定,但函数式不是,确切的说函数式 函数与数据等价,所以你才可以将函数当参数与返回值,你在设计时,切勿让数据自己长腿能跑,其次,行为必须消除副作用,不可以偷偷把数据改了,习惯第一条后,应该不会的
2.高阶逻辑
用
了函数式,就不要在想循环,赋值这些低阶逻辑了,而应该更高阶的思考问题,这比转化表达式更难,函数式又叫声明式,也就是你要做什么,只要说一下就行,而
非写个遍历,做个状态判断,用函数式你不需要考虑这些,你不知道函数式的列表是怎么遍历的,中间向两边?
从后往前?这也是为何函数式适合并发的原因之一,你想知道列表中大于3的数有多少,只要,list.count(_ > 3)
而不是写循环,你可以直接写你的业务,不要拘泥于细节,有点像sql, 你需要什么告诉电脑就行,你或许会问,count foreach filter
这些函数怎么来的? 因为有了他们你才不需要写循环,他们把你留在高阶逻辑中,这个问题的答案请看下面
3.组合子逻辑 或又叫 自底向上的设计
函
数式和OO是反的,面向对象是自顶向下的设计,函数式是自底向上的设计,也就是先定义最基本的操作,然后不断组合,不断堆积以满足你的所有需要,如sql
定义了select, from, where...这几个组合子,来满足你的查询需求,同理函数式语言会提供foreach,
map等组合子(操作)来满足你的需求,所以你必须自下而上的设计你的代码结构,并且满足你的需求,当你只用组合子写代码时,你会发现你写的全是高阶逻辑
如
果这些已有组合子满足不了你,你就得自己写,foreach不行,你就自己写递归,我告诉你,递归背后也是组合子,这里一些'大神'应该不知道,在图灵机
里,递归就是方法不断调用自己没什么好说的,但是在lambda演算中,匿名函数是没法调用自己的,所以递归是用Y组合子(又叫不动点组合子)把递归函数
自己求解出来再调用的,这才可以实现递归,并与图灵机的循环等价,有点跑题了,总之要想顺手的写函数式,最好用面向组合子的设计,注意,不是必须,组合子
演算和lambda演算可以相互转化,也就是,你完全可以写一堆杂乱的表达式,但没有组合子逻辑来得清爽,Haskell大规模使用monad这个特殊组
合子,始其变得统一整洁
好了,总结一下
函数式思维,其实就是组合子逻辑,用简单的几个函数组合来构建复杂逻辑,始终以高阶的角度去表达问题,而非依赖副作用。
知道这点,你用java也可以写函数式代码了
但是,这也只是本人积累得来的感悟,绝不敢大肆伸张这就是函数式,我也在不断研究中,如有问题,还望大神指正
『叁』 Java函数式编程语言是什么
函数式编程语言的核心是它以处理数据的方式处理代码。这意味着函数应该是第一等级(First-class)的值,并且能够被赋值给变量,传递给函数等等。
事实上,很多函数式语言比这走得更远,将计算和算法看得比它们操作的数据更重要。其中有些语言想分离程序状态和函数(以一种看起来有点对立的方式,使用面向对象的语言,这通常会将它们联系得更紧密)。
Clojure编程语言就是一个这样的例子,尽管它运行于基于类的Java虚拟机,Clojure的本质是函数式语言,并且在高级语言源程序中不直接公布类和对象(尽管提供了与Java良好的互操作性)。