新書推薦:
《
量子纠缠
》
售價:NT$
296.0
《
黑暗王后:缔造中世纪世界的血腥竞争
》
售價:NT$
602.0
《
诡舍(夜来风雨声悬疑幻想震撼之作)
》
售價:NT$
254.0
《
助人技术本土化的刻意练习
》
售價:NT$
408.0
《
中国历代户口、田地、田赋统计——梁方仲著作集
》
售價:NT$
689.0
《
帝国作为装饰品:英国人眼中的大英帝国(帝国与国际法译丛)
》
售價:NT$
403.0
《
AI芯片应用开发实践:深度学习算法与芯片设计
》
售價:NT$
352.0
《
世界之中(文明三部曲之后,亚洲图书奖得主张笑宇充满想象力的重磅新作)
》
售價:NT$
403.0
編輯推薦:
目前,C 、Scala、Java、C#、Python等高级编程语言也设计了函数式编程语言特性。但函数式编程语言设计思想抽象,特性比较多,这给很多读者带来了很大的困扰,尤其是涉及并发的编程,已成为很多人的梦魇。本书以图解方式,以Scala和Java语言作为实现载体,通过大量的代码示例和案例呈现出了函数式编程语言的特性。本书内容比较基础,建议读完本书的读者阅读《函数式与并发编程》(Functional and Concurrent Programming),该书与本书一脉相承,都以Scala和Java作为示例,主要围绕函数式编程和并发编程高级特性展开讲解。本书适合计算机科学与工程、软件工程、人工智能专业的高年级本科生和企业中对函数式编程感兴趣的工程师阅读。
內容簡介:
《函数式编程图解》旨在以通俗易懂的方式向命令式开发人员介绍函数式编程。从简短的编程任务开始,逐一引入诸如纯函数和不可变数据等基本概念,并在此过程中穿插讲解如何消除由复杂分布式状态引起的常见错误,适时探索IO、并发和数据流的函数式处理方式。读完本书后,你便能轻松编写出易于理解、测试和维护的简洁函数式代码。
主要内容
?使用函数和类型(而非对象)进行设计
?使用纯函数和不可变值进行编程
?编写函数式风格的并发程序
?测试函数式程序
關於作者:
Micha? P?achta是一位经验丰富的软件工程师,也活跃于函数式编程社区。他经常在技术会议上发言,主持研讨会,组织聚会,并在博客上发表文章,探讨如何创建可维护的软件。
目錄 :
第I部分 函数式工具包
第1章 学习函数式编程 3
1.1 也许你选择本书是因为……4
1.2 你应掌握的背景知识 5
1.3 函数是什么样的 6
1.4 认识函数 7
1.5 当代码说谎时…… 8
1.6 命令式与声明式 9
1.7 小憩片刻:命令式与声明式 10
1.8 解释:命令式与声明式 11
1.9 学习函数式编程的益处 12
1.10 进入Scala 13
1.11 练习用Scala编写函数 14
1.12 准备工具 15
1.13 了解REPL 16
1.14 编写你的第一个函数 17
1.15 如何使用本书 18
小结 19
第2章 纯函数 21
2.1 为什么需要纯函数 22
2.2 命令式编码 23
2.3 破译代码 24
2.4 传递数据的副本 25
2.5 再次破译代码…… 26
2.6 重新计算而不是存储 27
2.7 通过传递状态来集中于逻辑 28
2.8 状态去哪儿了 29
2.9 纯函数和非纯函数之间的区别 30
2.10 小憩片刻:将命令式代码重构为纯函数 31
2.11 解释:将命令式代码重构为纯函数 32
2.12 纯函数是值得信任的 34
2.13 程序语言中的纯函数 35
2.14 保持纯函数的难度…… 36
2.15 纯函数和清洁代码 37
2.16 小憩片刻:纯函数还是非纯函数 38
2.17 解释:纯函数还是非纯函数 39
2.18 使用Scala编写纯函数 40
2.19 用Scala练习纯函数 41
2.20 测试纯函数 42
2.21 小憩片刻:测试纯函数 43
2.22 解释:测试纯函数 44
小结 45
第3章 不可变值 47
3.1 引擎的燃料 48
3.2 不可变性的另一种情况 49
3.3 你会相信这个函数吗 50
3.4 可变性是危险的 51
3.5 回顾:说谎的函数…… 52
3.6 使用副本对抗可变性 53
3.7 小憩片刻:可变性带来的困扰 54
3.8 解释:可变性带来的困扰 55
3.9 引入共享可变状态 58
3.10 状态对编程能力的影响 59
3.11 处理移动部分 60
3.12 使用FP处理移动部分 61
3.13 Scala中的不可变值 62
3.14 建立对不可变性的直觉 63
3.15 小憩片刻:不可变的
String API 64
3.16 解释:不可变的String API 65
3.17 等等,这不是更糟糕吗 66
3.18 纯函数解法解决共享可变状态问题 67
3.19 练习不可变的切分和追加 69
小结 70
第4章 函数作为值 71
4.1 将要求实现为函数 72
4.2 非纯函数和可变值反击 73
4.3 使用Java Streams对列表进行排序 74
4.4 函数特征标记应说明全部情况 75
4.5 更改要求 76
4.6 只是在传递代码 77
4.7 使用Java的Function值 78
4.8 使用Function语法处理代码重复问题 79
4.9 将用户定义的函数作为参数传递 80
4.10 小憩片刻:将函数作为参数 81
4.11 解释:将函数作为参数 82
4.12 阅读函数式Java的问题 83
4.13 在Scala中传递函数 84
4.14 深入了解sortBy 85
4.15 在Scala中具有函数参数的特征标记 86
4.16 在Scala中将函数作为参数传递 87
4.17 练习函数传递 88
4.18 采用声明式编程 89
4.19 将函数传递给自定义函数 90
4.20 小函数及其职责 91
4.21 内联传递函数 92
4.22 小憩片刻:在Scala中传递函数 93
4.23 解释:在Scala中传递函数 94
4.24 仅通过传递函数还能实现什么功能呢 95
4.25 将函数应用于列表中的每个元素 96
4.26 使用map将函数应用于列表的每个元素 97
4.27 了解map 98
4.28 练习使用map 99
4.29 学习一次,随处适用 100
4.30 根据条件返回列表的部分内容 101
4.31 使用filter返回列表的部分内容 102
4.32 了解filter 103
4.33 练习filter 104
4.34 迄今为止的旅程…… 105
4.35 避免重复自己 106
4.36 API是否易于使用 107
4.37 添加一个新参数不足以解决问题 108
4.38 函数可以返回函数 109
4.39 使用可以返回函数的函数 110
4.40 函数就是值 111
4.41 小憩片刻:返回函数 112
4.42 解释:返回函数 113
4.43 设计函数式API 114
4.44 函数式API的迭代设计 115
4.45 从返回的函数中返回函数 116
4.46 如何从返回的函数中返回函数 117
4.47 使用返回函数构建的灵活API 118
4.48 在函数中使用多个参数列表 119
4.49 使用柯里化 120
4.50 练习柯里化 121
4.51 通过传递函数值进行编程 122
4.52 将许多值缩减为单个值 123
4.53 使用foldLeft将多个值缩减为一个 124
4.54 了解foldLeft 125
4.55 foldLeft用者须知 126
4.56 练习foldLeft 127
4.57 建模不可变数据 128
4.58 使用具有高阶函数的求积类型 129
4.59 内联函数的更简洁语法 130
小结 131
第II部分 函数式程序
第5章 顺序程序 135
5.1 编写基于流水线的算法 136
5.2 根据小模块构建大型程序 137
5.3 命令式解法 138
5.4 flatten和flatMap 139
5.5 使用多个flatMap的实际案例 140
5.6 flatMap和列表大小的更改 141
5.7 小憩片刻:处理由列表组成的列表 142
5.8 解释:处理由列表组成的列表 143
5.9 连接的flatMap和map 144
5.10 嵌套的flatMap 145
5.11 依赖其他值的值 146
5.12 练习嵌套的flatMap 147
5.13 更好的嵌套 flatMap 语法 148
5.14 使用for推导式 149
5.15 小憩片刻:flatMap与for推导式 150
5.16 解释:flatMap与for推导式 151
5.17 了解for推导式 152
5.18 这不是你想要的for 153
5.19 在for推导式内部 154
5.20 更复杂的for推导式 155
5.21 使用for推导式检查所有组合 156
5.22 过滤技术 157
5.23 小憩片刻:过滤技术 158
5.24 解释:过滤技术 159
5.25 抽象化 160
5.26 比较map、foldLeft和flatMap 161
5.27 使用Set的for推导式 162
5.28 使用多种类型的for推导式 163
5.29 练习for推导式 164
5.30 再次定义for推导式 165
5.31 使用非集合类型的for推导式 166
5.32 避免null函数:Option类型 167
5.33 解析为流水线 168
5.34 小憩片刻:使用Option进行解析 169
5.35 解释:使用Option进行解析 170
小结 171
第6章 错误处理 173
6.1 从容处理许多不同的错误 174
6.2 是否可能处理所有问题 175
6.3 按照播出时长对电视节目列表进行排序 176
6.4 实现排序要求 177
6.5 处理来自外部世界的数据 178
6.6 函数式设计:利用小代码块构建 179
6.7 将String解析为不可变对象 180
6.8 解析一个List只是解析一个元素 181
6.9 将String解析为TvShow 182
6.10 如何处理潜在错误 183
6.11 返回null是不是一个好办法 184
6.12 如何更从容地处理潜在错误 185
6.13 实现返回Option的函数 186
6.14 Option强制处理可能的错误 187
6.15 基于小代码块进行构建 188
6.16 函数式设计是基于小代码块进行构建 189
6.17 编写一个小而安全的函数,使其返回一个Option 190
6.18 函数、值和表达式 192
6.19 练习返回Option的安全函数 193
6.20 错误如何传播 194
6.21 值代表错误 195
6.22 Option、for推导式和已检查的异常 196
6.23 已检查异常怎么样 197
6.24 条件恢复 198
6.25 使用命令式风格进行条件恢复 199
6.26 使用函数式的条件恢复 200
6.27 已检查异常不可组合,但Option可以 201
6.28 orElse的工作原理 202
6.29 练习函数式错误处理 203
6.30 即使存在错误,仍组合函数 204
6.31 编译器提醒需要覆盖错误 205
6.32 编译错误对我们有好处 206
6.33 将由Option组成的List转换为扁平 List 207
6.34 让编译器成为我们的向导 208
6.35 不要过于相信编译器 209
6.36 小憩片刻:错误处理策略 210
6.37 解释:错误处理策略 211
6.38 两种不同的错误处理策略 212
6.39 孤注一掷错误处理策略 213
6.40 将Option组成的List折叠为一个List的Option 214
6.41 现已知道如何处理多个可能的错误 215
6.42 如何知道哪里出错了 216
6.43 需要在返回值中传达错误的详细信息 217
6.44 使用Either传达错误详情 218
6.45 重构以使用Either 219
6.46 返回Either而不是Option 220
6.47 练习返回Either的安全函数 223
6.48 学到的Option相关知识也适用于Either 224
6.49 小憩片刻:使用Either进行错误处理 225
6.50 解释:用Either进行错误处理 226
6.51 使用Option/Either进行工作 227
小结 228
第7章 作为类型的要求 229
7.1 建模数据以尽量减少程序员的错误 230
7.2 精心建模的数据不会说谎 231
7.3 使用已知内容(即原始类型)进行设计 232
7.4 使用建模为原始类型的数据 233
7.5 小憩片刻:原始类型之苦 234
7.6 解释:原始类型之苦 235
7.7 使用原始类型建模的问题 236
7.8 使用原始类型加大工作难度 237
7.9 newtype使参数不被错放 238
7.10 在数据模型中使用newtype 239
7.11 练习newtype 240
7.12 确保只存在有效数据组合 241
7.13 建模数据缺失的可能性 242
7.14 模型变化导致逻辑变化 243
7.15 在逻辑中使用建模为Option的数据 244
7.16 高阶函数获胜 245
7.17 可能存在符合要求的高阶函数 246
7.18 小憩片刻:forall/exists/contains 247
7.19 解释:forall/exists/contains 248
7.20 将概念耦合在单个求积类型内 249
7.21 建模有限可能性 250
7.22 使用求和类型 251
7.23 使用求和类型改善模型 252
7.24 使用“求和类型 求积类型”的组合 253
7.25 求积类型 求和类型=代数数据类型 254
7.26 在行为(函数)中使用基于ADT的模型 255
7.27 使用模式匹配解构ADT 256
7.28 重复和DRY 257
7.29 练习模式匹配 258
7.30 实际应用中的newtype、ADT和模式匹配 259
7.31 如何继承呢 260
7.32 小憩片刻:函数式数据设计 261
7.33 解释:函数式数据设计 262
7.34 建模行为 263
7.35 将行为建模为数据 264
7.36 使用基于ADT的参数实现函数 265
7.37 小憩片刻:设计与可维护性 266
7.38 解释:设计与可维护性 267
小结 268
第8章 作为值的IO 269
8.1 与外界交流 270
8.2 与外部 API 集成 271
8.3 具有副作用的IO操作的属性 272
8.4 带有副作用的IO代码的命令式解决方案 273
8.5 命令式IO方案存在许多问题 274
8.6 能通过FP完善方案吗 275
8.7 执行IO与使用IO的结果 276
8.8 命令式处理IO 277
8.9 作为IO值的计算 278
8.10 IO 值 279
8.11 实际运行中的IO值 280
8.12 将非纯性排出 281
8.13 使用从两个IO操作获取的值 282
8.14 将两个IO值组合成单个IO值 283
8.15 练习创建和组合IO值 284
8.16 仅使用值来解决问题 285
8.17 IO类型是病毒性的 286
8.18 小憩片刻:使用值 287
8.19 解释:使用值 288
8.20 向函数式IO前进 289
8.21 如何处理IO故障 290
8.22 运行由IO描述的程序可能会失败 291
8.23 记得orElse吗 292
8.24 惰性求值和及早求值 293
8.25 使用IO.orElse实现恢复策略 294
8.26 使用orElse和pure实现回退 295
8.27 练习IO值的故障恢复 296
8.28 应该在哪里处理潜在的故障 297
8.29 具有故障处理的函数IO 298
8.30 纯函数不会说谎,即使在
不安全的世界中也是如此 299
8.31 函数式架构 300
8.32 使用IO存储数据 301
8.33 小憩片刻:使用IO存储数据 304
8.34 解释:使用IO存储数据 305
8.35 将一切视为值 306
8.36 将重试作为值处理 307
8.37 将未知数量的API调用视为值 309
8.38 练习:培养函数特征标记的直觉 311
小结 312
第9章 作为值的流 313
9.1 无限超越 314
9.2 处理未知数量的值 315
9.3 处理外部非纯的API调用(再次) 316
9.4 函数式设计方案 317
9.5 不可变映射 318
9.6 练习不可变映射 319
9.7 应该进行多少IO调用 320
9.8 自下而上的设计 321
9.9 高级列表操作 322
9.10 引入元组 323
9.11 zip和drop 324
9.12 元组模式匹配 325
9.13 小憩片刻:使用映射和元组 326
9.14 解释:使用映射和元组 327
9.15 函数拼图 328
9.16 跟踪自下而上设计中的类型 329
9.17 原型制作和死胡同 330
9.18 递归函数 331
9.19 无限和惰性 332
9.20 递归函数结构 333
9.21 处理未来的空值(使用递归函数) 334
9.22 无限递归调用的有用性 335
9.23 小憩片刻:递归和无限 336
9.24 解释:递归和无限 337
9.25 使用递归创建不同的IO程序 338
9.26 使用递归进行任意数量的调用 339
9.27 递归版本的问题 340
9.28 引入数据流 341
9.29 命令式语言中的Stream 342
9.30 按需生成值 343
9.31 流处理、生产者和消费者 344
9.32 流和IO 345
9.33 函数式Stream 346
9.34 FP中的流是值 347
9.35 流是递归值 348
9.36 原始操作和组合器 349
9.37 基于IO值的流 350
9.38 基于IO值的无限流 351
9.39 为副作用而执行 352
9.40 练习流操作 353
9.41 利用流的功能 354
9.42 API调用的无限流 355
9.43 在流中处理IO故障 356
9.44 分离的关注点 357
9.45 滑动窗口 358
9.46 等待IO调用 360
9.47 组合流 361
9.48 使用基于流的方案的好处 362
小结 363
第10章 并发程序 365
10.1 无处不在的线程 366
10.2 声明式并发 367
10.3 顺序与并发 368
10.4 小憩片刻:顺序性思考 369
10.5 解释:顺序性思考 370
10.6 需要进行批处理 371
10.7 批处理实现 372
10.8 并发世界 373
10.9 并发状态 374
10.10 命令式并发 375
10.11 原子引用 377
10.12 引入Ref 378
10.13 更新Ref值 379
10.14 使用Ref值 380
10.15 让一切并行运行 381
10.16 parSequence的实际应用 382
10.17 练习并发IO 384
10.18 建模并发性 385
10.19 使用Ref和Fiber进行编码 386
10.20 无限运行的IO 388
10.21 小憩片刻:并发性思考 389
10.22 解释:并发性思考 390
10.23 需要异步性 391
10.24 为异步访问做准备 392
10.25 设计函数式异步程序 393
10.26 手动管理Fiber 394
10.27 编写函数式异步程序 395
小结 396
第III部分 应用函数式编程
第11章 设计函数式程序 399
11.1 有效、准确、快速 400
11.2 使用不可变值建模 401
11.3 业务领域建模和FP 402
11.4 数据访问建模 403
11.5 函数包 404
11.6 作为纯函数的业务逻辑 405
11.7 分离真正的数据访问问题 406
11.8 使用命令式库和IO与API集成 407
11.9 遵循设计 410
11.10 将输入操作作为IO值实现 411
11.11 将库IO与其他关注点分离 413
11.12 柯里化和控制反转 414
11.13 作为值的函数 415
11.14 串联知识 416
11.15 我们做到了 417
11.16 使业务逻辑正确 418
11.17 资源泄漏 419
11.18 处理资源 420
11.19 使用Resource值 421
11.20 我们做对了 422
11.21 小憩片刻:加快速度 423
11.22 解释:加快速度 424
小结 425
第12章 测试函数式程序 427
12.1 你对其进行测试吗 428
12.2 测试只是函数 429
12.3 选择要测试的函数 430
12.4 提供示例进行测试 431
12.5 通过示例练习测试 432
12.6 生成好示例 433
12.7 生成属性 434
12.8 基于属性的测试 435
12.9 提供属性进行测试 436
12.10 通过传递函数来委派工作 437
12.11 了解基于属性测试的失败原因 438
12.12 测试错误还是存在错误 439
12.13 自定义生成器 440
12.14 使用自定义生成器 441
12.15 以可读的方式测试更复杂的场景 442
12.16 查找并修复实现中的错误 443
12.17 小憩片刻:基于属性的测试 444
12.18 解释:基于属性的测试 445
12.19 属性和示例 446
12.20 要求范围 447
12.21 测试具有副作用的要求 448
12.22 确定工作所需的正确测试 449
12.23 数据使用测试 450
12.24 练习使用IO存根外部服务 452
12.25 测试和设计 453
12.26 服务集成测试 454
12.27 本地服务器作为集成测试中的资源 455
12.28 编写单独集成测试 456
12.29 与服务集成是单一职责 457
12.30 小憩片刻:编写集成测试 458
12.31 解释:编写集成测试 459
12.32 集成测试耗时更长 460
12.33 基于属性的集成测试 461
12.34 选择正确的测试方案 462
12.35 测试驱动开发 463
12.36 为不存在的功能编写测试 464
12.37 红绿重构 465
12.38 让测试通过 466
12.39 增加红色测试 467
12.40 最后的TDD迭代 468
小结 469
结语 470
——以下内容可通过扫描封底二维码下载——
附录A Scala 速查表 471
附录B 函数式重点 477
內容試閱 :
你好!感谢购买《函数式编程图解》。过去十年,我一直在与程序员讨论编程方法、其可维护性以及函数式编程概念逐渐被主流语言所采用这一趋势。许多专业开发人员表示,目前仍然很难从现有资源中学习函数式概念,因为这些资源要么过于简单,要么过于复杂。这就是本书试图填补的空白。本书旨在为那些想要全面了解基本函数式编程概念的程序员提供一种循序渐进的实用指南。
实践出真知,这就是本书大量使用实例的原因。读完这本入门书后,你将能够使用函数式方案编写功能齐全的程序,并轻松深入研究其理论基础。
如果你曾使用命令式面向对象语言(如Java或Ruby)创建重要的应用程序,那么你将从本书中获益匪浅。如果你所在的团队曾应对大量错误和可维护性问题,那么本书将是你的一大助力,因为这正是函数式编程的用武之地。
希望你喜欢阅读本书并完成习题,最好能像我写作时一样享受。再次感谢你对本书的喜爱!
——Micha? P?achta