返回首页

什么是函数式编程思维

241 2024-04-01 13:13 admin

回答都有跑题,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也可以写函数式代码了

但是,这也只是本人积累得来的感悟,绝不敢大肆伸张这就是函数式,我也在不断研究中,如有问题,还望大神指正

按照百度百科,据说函数式编程是计算机把运算当做函数处理。我本人用过一年左右Haskell(一种函数式编程语言),感觉有这些特点:

1 支持lamda表达式运算(lamda表达式的特点是替代运算,比如λx.xx的含义是属于输入x,结果是xx,如果有一个表达式为(λx.xx)y,函数是(λx.xx),输入是y,则结果是yy。

2 写不了循环,都用递归弄。

3 没有办法直接改全局变量,你只能把修改全局变量的函数传进函数操作(如果你有n个全局变量在一个函数中使用,在haskell中你要穿长度为n的数据量,这使得代码冗余,不过也保障了线程安全)。

4 高阶函数让一切变得方便,你可以把函数当做参数传入高阶函数(比如fmap,map,zip,fold等等),然后把传入的函数应用到传入的数据结构里,有点像C的函数指针。比如map可以把(a->b,输入a类型数据返回b类型数据)类型函数作用于整个数据类型为a的数组,map函数吧a->b类型函数作用于a类型数组中的每一项,然后返回类型为b的结果集。

5 对泛型的支持友好,你可以同时在函数声明中定义a类型b类型,数据类型安全有保障。更有甚者,在另外一个函数式编程语言idris中,数据类型(比如int)可以当成数据使用(这是很多程序语言都没有的)。

6 就Haskell而言,数据类型定义很灵活,对于除法,你可以用haskell自带的maybe类型(比如maybe double)作为返回类型,如果是有效值a就返回(Just a),如果是除0,你可以让结果返回Nothing。

7 Haskell中有一类东西叫type class,和Java里面的抽象类或者接口很像。如果你有数据类型a,b实现了一种type class(叫他class)的所有函数, 你可以把class里面定义的抽象函数用于a,b。这是多态的支持。如果你学得足够高深,函数式编程里面的Monad,Arrows等type class将会是你的常用技巧。

8 惰性求值。你可以定义一个无限长自然数表。如果你直接打印它,电脑尽其所能从0,1,2开始输出到内存溢出或者系统自己停止为止。如果你用了take函数,你可以之选择取前面5个值。此时电脑只生成0到4的表,因为从5开始数据没有用了。这可以大幅提升运行速度。

我说的这些都是在去年一年对函数式编程学习的小总结。需要学习的话,你可以上Hoogle(这不是google,一个haskell的官方API网站)查你不会的函数。

顶一下
(0)
0%
踩一下
(0)
0%
相关评论
我要评论
用户名: 验证码:点击我更换图片
上一篇:返回栏目
下一篇:什么是swift?