左耳听风
陈皓
网名“左耳朵耗子”,资深技术专家,骨灰级程序员
立即订阅
40357 人已学习
课程目录
已完结 108 讲
0/6登录后,你可以任选6讲全文学习。
开篇词 | 洞悉技术的本质,享受科技的乐趣
免费
01 | 程序员如何用技术变现(上)
02 | 程序员如何用技术变现(下)
03 | Equifax信息泄露始末
04 | 从Equifax信息泄露看数据安全
05 | 何为技术领导力?
06 | 如何才能拥有技术领导力?
07 | 推荐阅读:每个程序员都该知道的知识
08 | Go语言,Docker和新技术
09 | 答疑解惑:渴望、热情和选择
10 | 如何成为一个大家愿意追随的Leader?
11 | 程序中的错误处理:错误返回码和异常捕捉
12 | 程序中的错误处理:异步编程以及我的最佳实践
13 | 魔数 0x5f3759df
14 | 推荐阅读:机器学习101
15 | 时间管理:同扭曲时间的事儿抗争
16 | 时间管理:如何利用好自己的时间?
17 | 故障处理最佳实践:应对故障
18 | 故障处理最佳实践:故障改进
19 | 答疑解惑:我们应该能够识别的表象和本质
20 | Git协同工作流,你该怎么选?
21 | 分布式系统架构的冰与火
22 | 从亚马逊的实践,谈分布式系统的难点
23 | 分布式系统的技术栈
24 | 分布式系统关键技术:全栈监控
25 | 分布式系统关键技术:服务调度
26 | 分布式系统关键技术:流量与数据调度
27 | 洞悉PaaS平台的本质
28 | 推荐阅读:分布式系统架构经典资料
29 | 推荐阅读:分布式数据调度相关论文
30 | 编程范式游记(1)- 起源
31 | 编程范式游记(2)- 泛型编程
32 | 编程范式游记(3) - 类型系统和泛型的本质
33 | 编程范式游记(4)- 函数式编程
34 | 编程范式游记(5)- 修饰器模式
35 | 编程范式游记(6)- 面向对象编程
36 | 编程范式游记(7)- 基于原型的编程范式
37 | 编程范式游记(8)- Go 语言的委托模式
38 | 编程范式游记(9)- 编程的本质
39 | 编程范式游记(10)- 逻辑编程范式
40 | 编程范式游记(11)- 程序世界里的编程范式
41 | 弹力设计篇之“认识故障和弹力设计”
42 | 弹力设计篇之“隔离设计”
43 | 弹力设计篇之“异步通讯设计”
44 | 弹力设计篇之“幂等性设计”
45 | 弹力设计篇之“服务的状态”
46 | 弹力设计篇之“补偿事务”
47 | 弹力设计篇之“重试设计”
48 | 弹力设计篇之“熔断设计”
49 | 弹力设计篇之“限流设计”
50 | 弹力设计篇之“降级设计”
51 | 弹力设计篇之“弹力设计总结”
52 | 管理设计篇之“分布式锁”
53 | 管理设计篇之“配置中心”
54 | 管理设计篇之“边车模式”
55 | 管理设计篇之“服务网格”
56 | 管理设计篇之“网关模式”
57 | 管理设计篇之“部署升级策略”
58 | 性能设计篇之“缓存”
59 | 性能设计篇之“异步处理”
60 | 性能设计篇之“数据库扩展”
61 | 性能设计篇之“秒杀”
62 | 性能设计篇之“边缘计算”
63 | 区块链技术的本质
64 | 区块链技术细节:哈希算法
65 | 区块链技术细节:加密和挖矿
66 | 区块链技术细节:去中心化的共识机制
67 | 区块链技术细节:智能合约
68 | 区块链技术 - 传统金融和虚拟货币
69 | 程序员练级攻略:开篇词
70 | 程序员练级攻略:零基础启蒙
71 | 程序员练级攻略:正式入门
72 | 程序员练级攻略:程序员修养
73 | 程序员练级攻略:编程语言
74 | 程序员练级攻略:理论学科
75 | 程序员练级攻略:系统知识
76 | 程序员练级攻略:软件设计
77 | 程序员练级攻略:Linux系统、内存和网络
78 | 程序员练级攻略:异步I/O模型和Lock-Free编程
79 | 程序员练级攻略:Java底层知识
80 | 程序员练级攻略:数据库
81 | 程序员练级攻略:分布式架构入门
82 | 程序员练级攻略:分布式架构经典图书和论文
83 | 程序员练级攻略:分布式架构工程设计
84 | 程序员练级攻略:微服务
85 | 程序员练级攻略:容器化和自动化运维
86 | 程序员练级攻略:机器学习和人工智能
87 | 程序员练级攻略:前端基础和底层原理
88 | 程序员练级攻略:前端性能优化和框架
89 | 程序员练级攻略:UI/UX设计
90 | 程序员练级攻略:技术资源集散地
91 | 程序员面试攻略:面试前的准备
92 | 程序员面试攻略:面试中的技巧
93 | 程序员面试攻略:面试风格
94 | 程序员面试攻略:实力才是王中王
95 | 高效学习:端正学习态度
96 | 高效学习:源头、原理和知识地图
97 | 高效学习:深度,归纳和坚持实践
98 | 高效学习:如何学习和阅读代码
99 | 高效学习:面对枯燥和量大的知识
左耳听风
登录|注册

33 | 编程范式游记(4)- 函数式编程

陈皓 2018-01-23
从前三章内容中,我们了解到,虽然 C 语言简单灵活,能够让程序员在高级语言特性之上轻松进行底层上的微观控制,被誉为“高级语言中的汇编语言”,但其基于过程和底层的设计初衷又成了它的短板。
在程序世界中,编程工作更多的是解决业务上的问题,而不是计算机的问题,我们需要更为贴近业务、更为抽象的语言,如典型的面向对象语言 C++ 和 Java 等。
C++ 很大程度上解决了 C 语言中的各种问题和不便,尤其是通过类、模板、虚函数和运行时识别等解决了 C 语言的泛型编程问题。然而,如何做更为抽象的泛型呢?答案就是函数式编程(Functional Programming)。

函数式编程

相对于计算机的历史而言,函数式编程其实是一个非常古老的概念。函数式编程的基础模型来源于 λ 演算,而 λ 演算并没有被设计在计算机上执行。它是由 Alonzo Church 和 Stephen Cole Kleene 在 20 世纪 30 年代引入的一套用于研究函数定义、函数应用和递归的形式系统。
如 Alonzo 所说,像 booleans、integers 或者其他的数据结构都可以被函数取代掉。
我们来看一下函数式编程,它的理念就来自于数学中的代数。
f(x)=5x^2+4x+3
g(x)=2f(x)+5=10x^2+8x+11
h(x)=f(x)+g(x)=15x^2+12x+14
假设 f(x) 是一个函数,g(x) 是第二个函数,把 f(x) 这个函数套下来,并展开。然后还可以定义一个由两个一元函数组合成的二元函数,还可以做递归,下面这个函数定义就是斐波那契数列。
f(x)=f(x-1)+f(x-2)
对于函数式编程来说,它只关心定义输入数据和输出数据相关的关系,数学表达式里面其实是在做一种映射(mapping),输入的数据和输出的数据关系是什么样的,是用函数来定义的
函数式编程有以下特点。
特征
stateless:函数不维护任何状态。函数式编程的核心精神是 stateless,简而言之就是它不能存在状态,打个比方,你给我数据我处理完扔出来。里面的数据是不变的。
immutable:输入数据是不能动的,动了输入数据就有危险,所以要返回新的数据集。
优势
没有状态就没有伤害。
并行执行无伤害。
Copy-Paste 重构代码无伤害。
函数的执行没有顺序上的问题。
函数式编程还带来了以下一些好处。
惰性求值。这需要编译器的支持,表达式不在它被绑定到变量之后就立即求值,而是在该值被取用的时候求值。也就是说,语句如 x:=expression; (把一个表达式的结果赋值给一个变量) 显式地调用这个表达式被计算并把结果放置到 x 中,但是先不管实际在 x 中的是什么,直到通过后面的表达式中到 x 的引用而有了对它的值的需求的时候,而后面表达式自身的求值也可以被延迟,最终为了生成让外界看到的某个符号而计算这个快速增长的依赖树。
确定性。所谓确定性,就是像在数学中那样,f(x) = y 这个函数无论在什么场景下,都会得到同样的结果,而不是像程序中的很多函数那样。同一个参数,在不同的场景下会计算出不同的结果,这个我们称之为函数的确定性。所谓不同的场景,就是我们的函数会根据运行中的状态信息的不同而发生变化。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《左耳听风》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(29)

  • 硕根
    同样是业务代码的实现(抛开框架,中间件,基础设施的研发),前端更多的是声明式,函数式,反应式的编程,后端更多的是面向过程,事务,对象的编程,不知道皓叔怎么看这种差异的根源?
    2018-01-23
    19
  • minghu6
    一直不太明白一点,函数式编程的特点之一就是就是immutable,这就是说函数总是应该返回新的值而不是修改旧的值。但是,如果要处理一个很大的list,深拷贝的代价是不是太大了?

    进一步说,在编程解决实际问题的时候,往往需要依赖第三方的库。一方面大多数的第三方的库往往不是函数式的,引入后就被传染,变成了有状态的,可变的;另一方面,很难找到多少维护良好的通用编程方面的函数式的库。初步学习过common lisp,clojure,以及prolog和erlang,感觉除了这些语言都被局限在了“学术研究”,”语言玩具“,以及由高手组成的小团体的内部“秘密“使用。(erlang还好一些,但是被局限在了很小的领域)。

    最后还是感觉,一门语言,语言特性再好,还是得有杀手级应用,就像支柱产业能带动一大量上下游的发展。就像clojure过去要是没有Storm,可能不会发展这么繁荣。

    个人现在最常用的跟函数式风格有关的还是Java8的stream操作,对于理清思路,减少代码,提高开发效率来说非常有帮助。
    2018-02-14
    2
    10
  • zcom
    之前一直不是很理解函数式编程,直到我看了sicp,推荐朋友们有时间可以去看看。当然在工作中很少用过函数式编程,所以耗子哥最后的问题我答不上来……
    2018-01-23
    6
  • wang
    在我看来,面向对象编程和函数式编程他们的关注点不一样,面向对象编程帮助你设计更复杂的应用程序,函数式编程帮助你简化更复杂的计算,我身为java后端,一直都是面向对象为主,函数式只是帮助我简化代码。
    2018-07-13
    5
  • mingshun
    从过程式编程、面向对象编程、函数式编程一路走来,已经回不去了。对比机械化的过程式编程和层级结构复杂的面向对象编程,函数式编程能够很自然地描述现实世界。特别是用了 Elixir 之后,深感世界本应如此。其 pipeline 设计用起来比其他语言更灵活些,加上继承了 Erlang 的面向进程编程,可直接使用 OTP 开发分布式应用,语法更加人性化,还提供宏作为元编程手段,原生函数库也非常丰富。
    当然也要承认 Elixir 还是很小众。要从底层更多地考虑机器运作的思维向更多地考虑现实问题的思维转换对大部分人来说有难度,毕竟需要转变的还有世界观,而不仅仅是换个编程语言那么简单。
    2018-05-13
    5
  • 五柳
    有幸得以做自己喜欢的事情。一路走来,先是过程式,后是面向对象式,现在则是函数式。每次转变都感觉焕然一新,思路上了一级台阶。

    函数式能帮我们更容易写出精简、易于复用的代码。优势耗子哥已经写的很详细了。我安利一下,学函数式,一定要了解一下 Elixir,会从新的角度理解编程。比如 Elixir 的 pipeline 的设计绝对会有所启发。

    语言不止是工具。语言和编程范式极大影响了我们的思维。
    2018-02-13
    5
  • JZ
    整体设计面向对象,细节能用函数式就用函数式,算法相关过程式。稍微复杂点的场景想使用纯函数式,必然绕不过monad,hkt这样的概念。为了追求函数式风格而把程序写的艰深难懂,我觉得不是一件值得夸耀的事。
    2018-01-25
    5
  • JK.Ryan
    很早就读过coolshell里那篇函数式编程,很受教,今天这篇又加了许多干货,很赞,特别是讲到分布式理论和我们微观处理,其实有异曲同工之处,很有共鸣~👍🏾
    2018-02-06
    4
  • 4Neutrino
    耗哥,尾递归的示例代码有一处笔误导致死循环,应为(> counter n)
    2018-07-09
    3
  • Yano
    Java服务端开发,还在使用jdk6。可以说我是完完全全面向对象的思维,对于java 8的函数式编程都没有搞透彻。这篇文章很赞!
    2018-01-24
    3
  • 郎哲
    Erlang程序员
    默默地走过 只提了一下Erlang…
    2018-01-23
    3
  • fulljay
    我做web前端开发的,我觉得面向对象和面向函数,应该结合一起,界面(对象)及对应的事件回调(对象的方法),但到了状态机的处理用pipeline(函数式),所以我会选择在命令式编程语言中使用函数式编程风格
    2018-09-08
    2
  • fsj
    现在有很多语言不仅提供了面向对象功能,也提供了函数式编程的功能(比如Swift),在合适的场景选择合适的编程范式就好,当然,统一的编程范式还是让人赏心悦目的
    2018-04-04
    2
  • ryerh
    @硕根
    我对这种现象的个人理解是,前端的业务特点是“单App、单节点、UI驱动”,后端的业务特点是“多Service、分布式、数据驱动”,业务特点上的不同导致彼此适应的范式不同。
    2018-01-25
    2
  • 涛哥迷妹
    请教下 将运算过程尽量写成一系列嵌套的函数调用, 例如文中的pipeline demo是3个函数进行嵌套,3个函数的入参数都是nums, 我的问题是: pipeline这种编程模型是否要求 所有链式函数中的入参格式都相同,因为入参需要一级一级向下传递
    2019-06-19
    1
  • escray
    这篇不太容易看懂,拖延了很久。其中的代码能够看懂,但是的确没有在工作中使用过函数式编程的语言,很久以前看过一点点 Lisp。

    之前用过一段 C# 语言,大概是到 .NET Framework 4.0 之后提供了一些类似于 lamda 的语法糖,以及 LINQ 之类的查询,感觉和这里的函数式编程有点类似。不过当时只是在编辑器插件的帮助下,将命令式(过程式)的语言,转换成函数式的。看上去的确简洁了不少,但是感觉调试起来比较困难。

    后来转而使用 Ruby,Ruby 本身也提供了类似于 map, reduce 之类的函数,似乎有函数式编程的影子。

    感觉似乎命令式编程和函数式编程又相互借鉴、互相印证的地方。

    函数式编程可能更适合高性能计算、或分布式领域,因为更容易发挥其优势。
    2019-06-09
    1
  • karas
    ```python3
    def move_car(car_positions):
    return map(lambda x:(x+1) if random() > 0.3 else x,car_positions)
    ```
    这段代码map出来貌似是`<map object at 0x7fec36218908>`这种对象,导致下一步解析state的时候无法解析,然而如果使用表达式`[x+1 if random() > 0.3 else x for x in car_positions]
    `就完全没问题返回的还是list,这啥原因,python版本的关系?
    2019-06-07
    1
    1
  • 北风一叶
    定义输入数据和输出数据相关的关系,数学表达式里面其实是在做一种映射(mapping),输入的数据和输出的数据关系是什么样的,是用函数来定义的

    2018-08-02
    1
  • 衡子
    过程式编程到函数式编程,不是一门语言的转换。写了两年的Scala,回过头来想想,最多的是用到了Scala提供的filter、map等函数,真正用函数思维去设计、处理问题还是少!
    2018-05-30
    1
  • 大黄
    一直对函数式编程一知半解,耗子哥的讲解实在太棒了,有种顿悟的感觉。
    2018-04-17
    1
收起评论
29
返回
顶部