Scala 05 —— 函数式编程底层逻辑
该文章来自2023/1/14的清华大学交叉信息学院助理教授——袁洋演讲。
@[TOC]
函数式编程
- 什么是函数式编程?
- y=f(x)
无副作用:
- y只是依赖x,不会依赖其他变量
- 确定性关系:重新跑100次代码,得到的结果是一样的
- 不会给世界带来副作用。算完f(x)然后就得到了y,其他什么都没变。
什么是副作用?
- ==读写数据,人机交互,网络传输==等等...本不应该出现在函数式编程中,它们可能会带来"脏东西"或不确定因素。
假如...副作用是必须的?
- 把脏东西推到边缘去
- 在代码核心使用纯函数式编程(无副作用)
- 加减乘除求和等等...
- 在代码边缘处做其他任务(有副作用)
- 写数据库、与服务器通信、获取数据等等
- 在代码核心使用纯函数式编程(无副作用)
有什么好处?
- 至少我们对于代码核心能有更好的论证
- 纯的函数式代码到底有多大好处?
核心代码块一定要大!
不应该只是min(x,y)
不应该只是List(12,3,4,5,6),map(a=>a*a)
函数的定义
函数式编程,函数的==输入输出必须有清晰定义==
- 输入是什么,输出是什么?
- 输入有哪些变量,它们分别是什么?
定义模糊的例子:
y=f(x,y,?) :第三个参数可能不存在
这种做法就不够函数式,因为它同时定义了
- y=f(x,y,z)
- y=f(x,y)
但是可以这么写:y=f(x,y,z=null)
- f有三个参数,第三个默认为null
函数是数据的函数,不是数字的函数
- 基本类型的操作用的不多
- 稍复杂的业务会涉及到更多自定义数据类型
- 函数可以看作是一个范畴到另一个范畴直接的映射,即函子
- 什么是范畴?
- 范畴就是==带有关系==的集合
- 有很多对象,对象与对象之间有关系
- 可以表示世界万物
- 范畴就是==带有关系==的集合
- 函数式编程在范畴之间跳来跳去,函数式编程以范畴论为理论基础
如何定义范畴?
- 常用方法:OOP
OOP和FP是否矛盾?
- 一个是操作对象
一个是操作内容
需求:实现从猫到狗的转变
- OOP和FP是互补的,相互结合的
- OOP定义范畴内部的关系
- FP定义范畴与范畴之间的关系
- 两者垂直互补
如何把业务逻辑做成纯函数式?
- 业务流程中的每个中间步骤的数据必须是良定义的(adj.的n.)
- 数据与数据之间的转换过程是确定性的。(A->...操作->B)
函数式编程是声明式的,有效解耦
- 声明式:我告诉你,我给你什么(输入),我要什么(输出),你怎么做的我不管
- API接口给定,实现你做,我之后会来测试
- 描述的不是一个业务需求,而是对象转换
- 适合代码复用
- 把一个长链条拆分成无数小的步骤
- 每个步骤都比较简单(函数式),容易验证
- 关注输入输出的对象而非过程,容易做到类型安全的严丝合缝
- 函数式编程的理想步骤:
1.定义业务逻辑中所有的数据格式
2.定义所有数据与数据的转换操作函数
3.根据业务逻辑要求,把函数串起来 - 先定框架,再定逻辑
- 是什么
- 为什么
- 怎么做
- 实现会变得很容易,更适合AI自动编程
把业务逻辑看成流水线
- 每个函数都是流水线的一环
- 每一环都会将产品(数据)加工成另一个数据
- 猫变成狗
- 尽量不使用全局变量
- 流水线上不会调用流水线之外的东西帮忙
- 不要使用var,使用val
- 函数式编程中没有变量,只有指代
- 变量是实现的方式,但不是业务逻辑本身
- 从范畴的角度很容易理解
- 先做对,再做快:因为效率导致的问题通常很容易被修复
全局变量
- 流水线上不会调用流水线之外的东西帮忙
- 不要使用var,使用val
- 函数式编程中没有变量,只有指代
- 变量是实现的方式,但不是业务逻辑本身
- 从范畴的角度很容易理解
- 先做对,再做快:因为效率导致的问题通常很容易被修复
- 先做对,再做快:因为效率导致的问题通常很容易被修复