一篇有关函数式编程的形象生动教程
函数式编程(FP)与面向对象编程(OOP)的诞生的时间差不多,但它最近才最受欢迎,特别是在JavaScript社区中,为什么?
我在00年代早期就学麻省理工学院。计算机程序的体系结构和解释(SICP)是我的教科书。所以我的第一个正式学习的编程语言是函数性的,然后我在工业界工作了十多年,几乎没有多少时间考虑过使用FP。当得知大学的教科书被认为是“函数性编程圣经”时很震惊。
别误会我的意思,这是一本很好的教科书。我敢肯定它会让我成为一个更好的程序员,但这并不是我需要经常在Java / ActionScript / PHP / Python / Ruby / JavaScript等职业生涯中使用的东西。
然后我在Wyncode Academy任教四年,并发现自己试图向新手解释FP概念。这很难 - 比OOP更难。
为什么FP比OOP更难?
相关问题:为什么FP需要这么长时间才能流行起来?
我们编码社区需要解决为什么FP难以教授。像一个宗教说教一样传播FP重复了同样的错误,导致FP长期在这个行业中萎靡不振。
对FP的许多介绍都遗漏了一些东西。它不仅仅是一种替代编程风格。这是一种新的思维方式,它代表的类似的技巧也可以与来自OOP背景的更有经验的程序员一起使用。
我在Wyncode中使用的技术之一就是讲述一个难以理解的概念时,首先让学生了解概念的背景以及 这个概念的大致样子(big picture),之后就更容易解释技术细节了。
大致样子(big picture):历史背景
计算机是如何工作的?最常见的(流行的?易于理解的?)计算模型是图灵机。FP程序员抱怨的状态正在图灵机中正视着我们。用于操作该机器的算法表示不同状态之间的转换,例如从打开 / 关闭 (1或0)的一些盒子到打开 / 关闭的一些其他盒子。
如果我们试图想象两个图灵机同时在同一磁带上运行,我们就可以开始理解为什么“共享状态”和OOP中的并发性都是难题。
图灵机是一台通用机器。它可用于解决每个可有效计算的数学和逻辑问题。这是个简单的操作集: 向左移动,向右移动,写点,读点,擦除点(增删改查CRUD)。 足以(给予足够的时间和资源)来解决宇宙中的每个数学问题。
这就是艾伦·图灵在1936年所证明的。
在许多方面,图灵机是计算机“工作”的方式。但这也是计算机的工作原理。但是还有另外一种理论:
电路是不同的计算模型。每个逻辑门(AND,OR,NAND,NOR,XOR等)都是纯函数。他们接受输入并产生没有副作用的输出。如果我们只有能够创建和组合这些“函数”,我们还可以解决宇宙中每个可解决的数学问题。这也是阿隆佐·邱奇在1936年证明的。
所以我们有两种不同的计算模型:图灵机的0和1(对象)和阿隆佐·邱奇用逻辑门(函数)构建的lambda演算。哪一个是正确的?
有一段时间,关于抽象图灵机是否能解决与lambda演算相同的数学问题(反之亦然)的辩论。最终他们被证明是等同的。
等同意味着它们同样强大。任何可以为图灵机编写的算法也可以使用函数编写。因此,任何可以用图灵机软件编写的程序也可以用电路硬件表示。
“硬件编程”是什么意思?我们可以看到专用集成电路(ASIC)中体现的“硬件编程” 。可以创建“编程”的电路,以便快速完成一件事,比如我的比特币或下棋。
我们现在有两种编程选择。硬件更快,软件更慢。在软件中犯了错误?只需点击删除键,然后重试。硬件出错?是时候抓烙铁了。这是一个经典的工程设计权衡。
因此,假设我们有一个以OOP风格编写的算法,我们希望将其转换为ASIC硬件编程。以FP风格重写程序可能是一个很好的策略,因此它可以更好地映射到底层电路图。
面向FP的语言往往看起来像电路。特别是Unix,Elixir,F#,JavaScript和其他“管道操作员” 使代码看起来像电路图:输入进入左侧,流过许多“门”(管道)直到它们被转换进入右边的最终输出。某些语言(|>)使用的管道运算符看起来像逻辑门,这可能不是巧合。
大致样子(big picture):哲学
我拿到了我的CS学位的哲学辅修,所以我着迷的一件事是这两个研究领域的交集。我发现在教授新程序员时,特别是那些具有人文学科而不是STEM背景的程序员,有助于在这两个领域重叠处讨论思想。
FP中一个哲学上重要的概念是“函数相等 functionally equivalent”。
也许证明这种等价性的最好例子是汤姆斯图尔特的伟大文章“从无开始编程”。这里借用他对数字如何完全用函数表示的方式来解释编码:
首先将数字0的概念定义为接受函数参数但不对其执行任何操作的函数。
# Ruby ZERO = -> (func) { # does nothing func }
类似地,我们可以将所有自然数定义为接受函数参数的函数,并将它们调用n次。
ONE = -> (func) { # calls it once # same as func.call() func[]; func } TWO = -> (func) { # calls it twice func[] func[] func }
要测试这些“函数数字”,请将它们传递给测试函数。
HELLO = ->() { puts "hello" } # same as: ZERO.call(HELLO) ZERO[HELLO] # nothing displayed ONE[HELLO] # one "hello" displayed TWO[HELLO] # "hello" twice
这种函数数字符号表示法其实很难玩和调试。因此,为了更容易使用,我们可以定义一个函数,将这些函数数转换为我们习惯使用的对象数字。
# convert number function into number object def to_integer(func) # count how many times counter is called n = 0 counter = ->() { n += 1 } func[counter] n end p to_integer(ZERO) # 0 p to_integer(ONE) # 1 p to_integer(TWO) # 2
这个转换器创建计数功能并将其传递给数字函数。ZERO函数将调用它为零次,ONE函数将调用它一次,等等。我们跟踪计数器被调用多少次以获得结果。
对于这些函数数字定义,我们可以实现添加各种功能:ADD SUM统计等。
ADD = -> (func1, func2) { -> (f) { func1[func2[f]] } } sum = ADD[ZERO, ZERO] p to_integer(sum) # 0 sum = ADD[ZERO, ONE] p to_integer(sum) # 1 sum = ADD[ONE, ONE] p to_integer(sum) # 2
如果TWO调用一个函数两次,那么ADD[TWO, TWO]将返回一个调用其参数四次的函数数字(函数数字FOUR)。
这是一个令人费解的方式。当我看完“从无开始编程”这本书时,我感觉这是一个巧妙应用基本计算机科学概念的有趣书籍,但不是我在日常工作中可以使用的东西。
而这正是我(我怀疑很多其他人)对FP一般的感觉 - 它很聪明,但似乎没有用。这是我们需要解决的问题。
所以,教FP更好的开始地方是“黑客帝国3:矩阵革命”。
什么是矩阵与FP呢? 这部电影告诉我们:我们没有证据证明我们周围的世界是真实的。也许世界上有实际的物体,或者我们只是在罐子里的大脑。
因此,至少有两个相互矛盾的理论,例如,第一个是什么。我们可以与之交互(触摸和感觉)是一种(名词,对象)吗?或者它是一个动作(一个动词,一个函数),一个作用于世界的东西,但没有实在的呈现?
函数数字one是数字1的模拟,它是在函数等同 functionally equivalent于对象数字one,意味着它可以做对象数字one做的任何事情。
但是OOP中的对象“存在”并不是真的“存在”。这是一个矩阵模拟。它没有固有属性 - 它不是x,它只是像x。
打个比喻,你坐在真正的椅子上只是一种用力按压你的身体功能?“椅子”可以是存在于现实世界中的椅子这个对象,也可以是一种椅子功能:一种希望用舒适的力量推动你的功能,并没有潜在的客观基础。
想想颜色,红色美味的苹果真的是红色的(形容词、描述名词)还是扮演红色(动词)?颜色是真正的底层苹果对象的固有属性,还是仅仅是当光照在它上面时执行函数的动作结果呢?苹果真的还是模拟的呢?
解释这个哲学概念的难度是解释为什么FP难以教授的好隐喻。为了帮助学生理解,首先要开放他们的想法,让世界完全由“功能/函数”组成。从样子big picture概念开始,然后转向世界的FP模型:它们与OOP表示的区别以及它们如何具有相同的结果。(banq注:从概念开始转向有两个:一个是名词,一个是动词,FP是转向到动词,而我们日常是转向名词,但是很多人没有意识到这种转向,所以很难转到动词方向去接受函数编程)
相关推荐
81540398 2020-09-04
Jruing 2020-11-01
89231645 2020-10-26
87204154 2020-09-24
81244053 2020-09-23
FalseNotFalse 2020-09-22
84423067 2020-06-12
hongbing 2020-06-02
huavhuahua 2020-05-11
samsai00 2020-05-06
猛禽的编程艺术 2020-04-23
上海滩 2020-04-22
斑点喵 2020-03-04
cuiguanjun 2020-03-01
TheBigBlue 2020-02-20
banzhihuanyu 2020-02-19
banzhihuanyu 2020-02-15
89510196 2020-02-06
banzhihuanyu 2020-01-31