文章目录:
一 、什么是函数式编程思维
按照百度百科 ,据说函数式编程是计算机把运算当做函数处理 。我本人用过一年左右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网站)查你不会的函数 。
二 、到底什么是函数式编程思维
形而上的思维:
1 、数据不可变的思维:let a = 100 ,意义不是把100赋值给变量a ,而是把a符号绑定(或者叫匹配)到100 。
2 、一切皆表达式思维:if b then 100 else 10 ,这不是条件跳转 ,而是一个三元表达式 。
3 、函数是第一类值:函数可以作为参数传输 ,也可以作为结果返回 ,更可以由一个函数演化成另一个函数 。
形而下的思维:
1 、用递归替换循环 。
2 、难以尾递归的时候考虑使用延续函数(continuation) 。
3 、高阶函数 、部分应用 、Lambda演算 。
4 、用泛型 、接口 、可区别联合类型替换类继承 。
5 、用二叉树替换普通链表后可以支持高并发计算 。
===================================================
这些也只是feature而不是思维 。我想知道的是这些feature之后的逻辑 。
-----------------------------------------------------------------------------------------------------
再往上说就不接地气了 ,先从函数式语言说起 ,函数式语言其实就是模仿人的数学思维而发明的朴素 ,后来因为离机器太远 ,不容易优化而被诟病 。但科技发展到今天 ,编译器的优化能力已经很强 ,软件系统越来越复杂 ,人的分工越来越细 ,函数式语言离数学更近 ,离机器更远 ,反而成为一种优势 ,有助于人把问题清晰化 。从这个层面看 ,函数式编程是一种什么思维 ,就是推离机器的数学思维 。这里没有内存 、寄存器的想法 ,在 a=1之后 ,a 就不可能再等于2 ,当然你可以在 let a = 1 之后 ,再 let a = 2 ,但是这个a 就已经不是那个a ,在停留在有内存概念的编程世界里 ,a 一直是 a ,它是装东西的桶或者盒子 ,只是每次里面装的东西不同 。
那么 ,总的来说 ,是先有朴素的函数式语言 ,然后才有今天发现函数式编程的好处 , 启用了函数式语言的某些 feature ,目的是为了把问题解构成更小的粒度 。所以这些feature背后没什么逻辑 ,就好像问这石头为什么长这样一样 。我只能打句偈语:本来就这样 。
三 、学习函数式编程的推荐书籍?
1 、关于书籍的选择
1) 、选择好学习的函数式编程语言后 ,可以根据自己的情况去一些书店 、网上商城(比京东 、当当)选择相应编程语言的书籍资料 。
2) 、如果从思想入手 ,并且希望学的更深入 ,个人建议从SICP(《计算机程序的构造和解释》)入手 ,Scheme语言是思想的锤炼 。
3) 、如果用户是java程序员 ,建议看看clojure ,这是个极具生产力的语言工具 ,它运行于java平台上的lisp 。twitter的storm就是用它写的 。clojure现在已经是黑客领域最耀眼的明星了 。最重要的是clojure已经出版了很多本中文教材 ,可以入手学习了 。顺带加上SICP可以加快学习进度 。以项目为中心可以选择《Clojure经典实例 功能性编程全面指南》 、没有基础的可以选择《Living Clojure》(中文版) 、老程序员可以参考《Clojure编程乐趣》中文版 。
4) 、如果不为作项目 ,只是为了提升个人的能力或者编程思想 ,可以选择haskell语言 ,这个资料也比较多 ,无论书籍还是视频 、文档等等 。
2 、简单说 ,"函数式编程"是一种"编程范式"(programming paradigm) ,也就是如何编写程序的方法论 。
它属于"结构化编程"的一种 ,主要思想是把运算过程尽量写成一系列嵌套的函数调用 。举例来说 ,现在有这样一个数学表达式:
(1 + 2) * 3 - 4传统的过程式编程 ,可能这样写:var a = 1 + 2;var b = a * 3;
var c = b - 4;
函数式编程要求使用函数 ,我们可以把运算过程定义为不同的函数 ,然后写成下面这样:var result = subtract(multiply(add(1 ,2) , 3) , 4);这就是函数式编程 。3 、函数编程的特点:
函数式编程具有五个鲜明的特点 。
1) 、 函数是"第一等公民"
所谓"第一等公民"(first class) ,指的是函数与其他数据类型一样 ,处于平等地位 ,可以赋值给其他变量 ,也可以作为参数 ,传入另一个函数 ,或者作为别的函数的返回值 。
举例来说 ,下面代码中的print变量就是一个函数 ,可以作为另一个函数的参数 。
var print = function(i){ console.log(i);};[1 ,2 ,3].forEach(print);
2) 、只用"表达式" ,不用"语句""表达式"(expression)是一个单纯的运算过程 ,总是有返回值;"语句"(statement)是执行某种操作 ,没有返回值 。函数式编程要求 ,只使用表达式 ,不使用语句 。也就是说 ,每一步都是单纯的运算 ,而且都有返回值 。
原因是函数式编程的开发动机 ,一开始就是为了处理运算(computation) ,不考虑系统的读写(I/O) 。"语句"属于对系统的读写操作 ,所以就被排斥在外 。
当然 ,实际应用中 ,不做I/O是不可能的 。因此 ,编程过程中 ,函数式编程只要求把I/O限制到最小 ,不要有不必要的读写行为 ,保持计算过程的单纯性 。
3) 、没有"副作用"
所谓"副作用"(side effect) ,指的是函数内部与外部互动(最典型的情况 ,就是修改全局变量的值) ,产生运算以外的其他结果 。
函数式编程强调没有"副作用" ,意味着函数要保持独立 ,所有功能就是返回一个新的值 ,没有其他行为 ,尤其是不得修改外部变量的值 。
4) 、不修改状态
上一点已经提到 ,函数式编程只是返回新的值 ,不修改系统变量 。因此 ,不修改变量 ,也是它的一个重要特点 。
在其他类型的语言中 ,变量往往用来保存"状态"(state) 。不修改变量 ,意味着状态不能保存在变量中 。函数式编程使用参数保存状态 ,最好的例子就是递归 。下面的代码是一个将字符串逆序排列的函数 ,它演示了不同的参数如何决定了运算所处的"状态" 。
function reverse(string) {if(string.length == 0) {
return string;
} else {
return reverse(string.substring(1 , string.length)) + string.substring(0 , 1);
}
}
由于使用了递归 ,函数式语言的运行速度比较慢 ,这是它长期不能在业界推广的主要原因 。5) 、引用透明
引用透明(Referential transparency) ,指的是函数的运行不依赖于外部变量或"状态" ,只依赖于输入的参数 ,任何时候只要参数相同 ,引用函数所得到的返回值总是相同的 。
有了前面的第三点和第四点 ,这点是很显然的 。其他类型的语言 ,函数的返回值往往与系统状态有关 ,不同的状态之下 ,返回值是不一样的 。这就叫"引用不透明" ,很不利于观察和理解程序的行为 。
到此 ,以上就是小编对于函数式编程思维 mobi的问题就介绍到这了 ,希望介绍关于函数式编程思维 mobi的3点解答对大家有用 。
留言评论
暂无留言