命令式编程 V.S. 声明式编程
Programming: Imperative & Declarative
- 命令式编程:“怎么做” —— 写给计算机的语言
- 声明式编程:“做什么” —— 写给人看的语言
思考下述问题:
检查 students 里的学生的平均分,并输出平均分的第一名。
先给定一些定义代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| struct Student { let name: String let scores: [Subject: Int] }
enum Subject: String, CaseIterable { case Chinese, Math, English }
let s1 = Student( name: "Foo", scores: [.Chinese: 86, .Math: 92, .English: 73] )
let s2 = Student( name: "Bar", scores: [.Chinese: 99, .Math: 52, .English: 97] )
let s3 = Student( name: "Joe", scores: [.Chinese: 91, .Math: 92, .English: 100] )
let students = [s1, s2, s3]
|
下面尝试分别用命令式编程和函数式编程解决:
命令式编程
一步步告诉计算机怎么做。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| var best: (Student, Double)?
for s in students { var totalScore = 0 for key in Subject.allCases { totalScore += s.scores[key] ?? 0 }
let averageScore = Double(totalScore) / Double(Subject.allCases.count)
if let temp = best { if averageScore > temp.1 { best = (s, averageScore) } } else { best = (s, averageScore) } }
print(best?.0.name ?? "no students")
|
这应该就是大多数同学所熟知的编程方式。
声明式编程
告诉计算机要做什么,具体实现由计算机决定。
函数式
1 2 3 4 5 6 7 8 9 10
|
func average(_ scores: [Subject: Int]) -> Double { return Double(scores.values.reduce(0, +)) / Double(Subject.allCases.count) }
let bestStudent = students .map { ($0, average($0.scores)) } .sorted { $0.1 > $1.1 } .first
|
(写在2021年1月:我是有点喜欢函数式啦,但 SICP 至今没看完。。)
Update(2021.07.18): 现在看完啦!!
我一直都很喜欢函数式,推荐大家去看 SICP(一定要把里面的代码自己写一遍,不然到后面就基本看不懂了)👀。
DSL
例如 SQL:
1 2
| select name, avg(score) as avs_score from scores group by name order by avg_score;
|
(不喜欢 SQL,我非常讨厌 group by
这种超过一个词的关键字,所以自己的项目天天用 ORM。。)
参考
王巍 (@onevcat)《SwiftUI 与 Combine 编程》Chapter 1