这既并不是一本Clojure入门手册,也不是一本Clojure的编程操作指南。这书根据对Clojure详细地研究,叙述涵数式的编程设计方法,协助读者了解和感受Clojure编程的快乐,从而开发设计出幽美的手机软件。
由福菲德、豪泽著的《Clojure编程乐趣(第2版)》分成六个一部分共17章。第一一部分是基本,包含第一~3章,从Clojure身后的观念刚开始,介绍了Clojure的基本知识,并领着读者基本试着Clojure编程。第二一部分是第四章和第五章,介绍了Clojure的各种各样基本数据类型。第三一部分是第六章和第7章,介绍了涵数式编程的特点。第四一部分是第八章~11章,各自介绍了宏、组成数据信息域代码、Clojure对Java的启用,及其并发编程等比较高級的话题讨论。第五一部分为第12章和第13章,讨论了Clojure的性能难题以及带来大家的思考。第六一部分为第14~17章,介绍了朝向数据信息编程、性能、思考程序流程及其Clojure的思考方法。
这书合适要想转为涵数式語言或开展并发编程的程序猿阅读文章,对JVM服务平台编程很感兴趣的程序猿,要想学习培训高级的Java程序流程及其Clojure的读者,均可以从这当中获利。
目录
- 第1部分 基 础
- 第1章 Clojure哲学 3
- 1.1 Clojure之道 4
- 1.1.1 简单 4
- 1.1.2 专注 5
- 1.1.3 实用 5
- 1.1.4 清晰 6
- 1.1.5 一致 7
- 1.2 为何(又一种)Lisp 8
- 1.2.1 优美 8
- 1.2.2 极度灵活 9
- 1.3 函数式编程 15
- 1.3.1 一个可行的函数式编程
- 定义 15
- 1.3.2 函数式编程的内涵 16
- 1.4 Clojure为何不是面向
- 对象的 16
- 1.4.1 定义术语 16
- 1.4.2 命令式“烘烤” 18
- 1.4.3 OOP提供的大多数东西,
- Clojure也有 18
- 1.5 小结 23
- 第2章 Clojure疾风式教程 24
- 2.1 基本数据类型 25
- 2.1.1 数字 25
- 2.1.2 整数 25
- 2.1.3 浮点数 26
- 2.1.4 有理数 26
- 2.1.5 符号 27
- 2.1.6 关键字 27
- 2.1.7 字符串 27
- 2.1.8 字符 28
- 2.2 组合起来:集合 28
- 2.2.1 list 28
- 2.2.2 vector 29
- 2.2.3 map 29
- 2.2.4 set 29
- 2.3 付诸实现:函数 29
- 2.4 var 30
- 2.5 函数 30
- 2.5.1 匿名函数 31
- 2.5.2 使用def和defn定义命名
- 函数 31
- 2.5.3 不同参数数量的函数 32
- 2.5.4 以#()定义原位(in-place)
- 函数 33
- 2.6 局部量、循环和block 33
- 2.6.1 block 34
- 2.6.2 局部量 34
- 2.6.3 循环 35
- 2.7 防止发生:quote 37
- 2.7.1 求值 37
- 2.7.2 Quoting 38
- 2.7.3 反quote 40
- 2.7.4 反quote拼接 41
- 2.7.5 auto-gensym 41
- 2.8 与Java互操作 41
- 2.8.1 访问静态类成员(仅限于
- Clojure) 41
- 2.8.2 创建Java实例 42
- 2.8.3 用.运算符访问Java实例
- 成员 42
- 2.8.4 设置Java实例属性 43
- 2.8.5 ..宏 43
- 2.8.6 doto宏 44
- 2.8.7 定义类 44
- 2.9 异常环境 44
- 2.10 命名空间 45
- 2.10.1 用ns创建命名空间 45
- 2.10.2 用:require加载其他命名
- 空间 46
- 2.10.3 用:refer加载和创建
- 映射 47
- 2.10.4 用:refer创建映射 47
- 2.10.5 用:import加载Java类 48
- 2.11 小结 48
- 第3章 小试牛刀 49
- 3.1 真值 50
- 3.1.1 什么是真 50
- 3.1.2 不要创建布尔对象 50
- 3.1.3 nil vs. false 51
- 3.2 小心翼翼nil双关 51
- 3.3 解构 53
- 3.3.1 你的任务,你应该选择
- 接受 53
- 3.3.2 解构vector 53
- 3.3.3 解构map 55
- 3.3.4 解构函数参数 57
- 3.3.5 解构vs.访问器方法 57
- 3.4 用REPL做试验 57
- 3.4.1 试验seq 57
- 3.4.2 试验图形化 59
- 3.4.3 知识汇总 60
- 3.4.4 出错之时 61
- 3.4.5 只为乐趣 62
- 3.5 小结 63
- 第2部分 数 据 类 型
- 第4章 标量 67
- 4.1 理解精度 68
- 4.1.1 截断(Truncation) 68
- 4.1.2 提升(Promotion) 69
- 4.1.3 上溢(Overflow) 69
- 4.1.4 下溢(Underflow) 70
- 4.1.5 舍入错误(Rounding
- errors) 70
- 4.2 有理数 71
- 4.2.1 为什么是有理数 71
- 4.2.2 怎样才是有理数 72
- 4.2.3 有理数的合理性 73
- 4.3 使用关键字的时机 73
- 4.3.1 关键字的应用 73
- 4.3.2 限定关键字 75
- 4.4 符号解析 76
- 4.4.1 元数据 77
- 4.4.2 符号与命名空间 78
- 4.4.3 Lisp-1 78
- 4.5 正则表达式——第二个
- 问题 79
- 4.5.1 语法 79
- 4.5.2 函数 80
- 4.5.3 小心可变匹配器
- (matcher) 81
- 4.6 总结 81
- 第5章 组合数据类型 82
- 5.1 持久化、序列和
- 复杂度 83
- 5.1.1 “你一直用着这个词。我认
- 为,这并不意味着它就是你
- 以为的含义” 83
- 5.1.2 序列术语及其含义 84
- 5.1.3 大O 87
- 5.2 vector:创建和使用其各种
- 变体 89
- 5.2.1 构建vector 89
- 5.2.2 大vector 90
- 5.2.3 vector当作栈 93
- 5.2.4 使用vector而非reverse 94
- 5.2.5 子vector 95
- 5.2.6 vector当作MapEntry 95
- 5.2.7 vector不是什么 96
- 5.3 list:Clojure代码form的
- 数据结构 97
- 5.3.1 像Lisp那样的list 97
- 5.3.2 list当作栈 98
- 5.3.3 list不是什么 98
- 5.4 如何使用持久化队列 99
- 5.4.1 什么都没有的队列 99
- 5.4.2 入队 100
- 5.4.3 获取 101
- 5.4.4 出队 101
- 5.5 持久化set 101
- 5.5.1 Clojure set的基本
- 属性 101
- 5.5.2 用sorted-set保持set的
- 顺序 103
- 5.5.3 contains 103
- 5.5.4 clojure.set 104
- 5.6 思考map 106
- 5.6.1 hash map 106
- 5.6.2 以有序map保持键值的
- 顺序 107
- 5.6.3 用数组map保持插入
- 顺序 108
- 5.7 知识汇总:在序列里查找
- 某项的位置 109
- 5.8 小结 111
- 第3部分 函数式编程
- 第6章 惰性与不变性 115
- 6.1 关于不变性:按照自己的
- 方式去使用 115
- 6.1.1 什么是不变性? 116
- 6.1.2 不变性可以做什么? 116
- 6.2 设计一个持久化
- 玩具 118
- 6.3 惰性 121
- 6.3.1 以“逻辑与”熟悉惰性 122
- 6.3.2 理解lazy-seq的秘诀 123
- 6.3.3 丢掉头 126
- 6.3.4 采用无限序列 126
- 6.3.5 delay和force宏 128
- 6.4 知识汇总:一个惰性的
- 快速排序程序 130
- 6.4 小结 133
- 第7章 函数式编程 134
- 7.1 各种形式的函数 134
- 7.1.1 一等函数 135
- 7.1.2 高阶函数 138
- 7.1.3 纯函数 141
- 7.1.4 命名实参 143
- 7.1.5 使用前置条件和后置条件
- 约束函数 143
- 7.2 闭包 145
- 7.2.1 函数返回闭包 146
- 7.2.2 隐藏参数 147
- 7.2.3 将闭包当作函数传递 148
- 7.3 递归思考 152
- 7.3.1 普通递归 152
- 7.3.2 尾递归和recur 155
- 7.3.3 勿忘trampoline 157
- 7.3.4 延续传递风格 159
- 7.4 知识汇总:A*寻路 161
- 7.4.1 世界 161
- 7.4.2 近邻 161
- 7.4.3 A*实现 163
- 7.4.4 A*实现的笔记 165
- 7.5 小结 166
- 第4部分 大规模设计
- 第8章 宏 169
- 8.1 数据即代码即数据 170
- 8.1.1 语法quote、反quote和
- 拼接 171
- 8.1.2 宏之经验谈 173
- 8.2 定义控制结构 173
- 8.2.1 不用语法quote定义控制
- 结构 174
- 8.2.2 使用语法quote和反quote
- 定义控制结构 175
- 8.3 组合form的宏 176
- 8.4 使用宏改变form 177
- 8.5 使用宏控制符号解析
- 时间 181
- 8.5.1 回指 181
- 8.5.2 (可能)有用的选择性名字
- 捕获 182
- 8.6 使用宏管理资源 183
- 8.7 知识汇总:返回函数的
- 宏 184
- 8.8 小结 187
- 第9章 组合数据与代码 188
- 9.1 命名空间 188
- 9.1.1 创建命名空间 189
- 9.1.2 只暴露所需 191
- 9.1.3 声明性包含和排除 194
- 9.2 以通用设计模式探索
- Clojure多重方法 194
- 9.2.1 组成部分 195
- 9.2.2 用法 196
- 9.2.3 以多重方法拯救 197
- 9.2.4 处理继承行为的特别
- 继承 197
- 9.2.5 解析层次中的冲突 198
- 9.2.6 真正的最大功率任意
- 分发 199
- 9.3 类型、协议和记录 200
- 9.3.1 记录 200
- 9.3.2 协议 203
- 9.3.3 用deftype从更原始的
- 基础开始构建 211
- 9.4 知识汇总:国际象棋
- 移动的流畅构建器 213
- 9.4.1 Java实现 213
- 9.4.2 Clojure实现 215
- 9.5 小结 217
- 第10章 变化和并发 218
- 10.1 使用Ref的时机 219
- 10.1.1 利用ref构建可变
- 棋盘 221
- 10.1.2 事务 223
- 10.1.3 嵌入式事务 225
- 10.1.4 STM使其简单的
- 事情 225
- 10.1.5 潜在缺陷 226
- 10.1.6 让STM不高兴的事 227
- 10.2 利用refs重构 228
- 10.2.1 解决棋盘例子 228
- 10.2.2 以commute进行可交换的
- 改变 230
- 10.2.3 以ref-set进行普通
- 改变 231
- 10.2.4 压力之下的Ref 232
- 10.3 使用Agent的时机 233
- 10.3.1 进程内并发模型vs分布式
- 并发模型 234
- 10.3.2 用Agent控制I/O 235
- 10.3.3 send和send-off之间的
- 差异 237
- 10.3.4 错误处理 239
- 10.3.5 何时不用Agent 241
- 10.4 使用Atom的时机 241
- 10.4.1 跨线程共享 242
- 10.4.2 在事务里使用Atom 242
- 10.5 使用lock的时机 244
- 10.5.1 使用锁进行安全
- 变化 245
- 10.5.2 使用Java的显式锁 246
- 10.6 var和动态绑定 248
- 10.6.1 binding宏 248
- 10.6.2 创建命名var 250
- 10.6.3 创建匿名var 251
- 10.6.4 动态作用域 251
- 10.7 小结 253
- 第11章 并行 254
- 11.1 使用future的时机 255
- 11.2 使用promise的
- 时机 259
- 11.2.1 以promise进行并行
- 任务 260
- 11.2.2 回调API到阻塞API 261
- 11.2.3 确定性死锁 262
- 11.3 并行 263
- 11.3.1 pvalues 263
- 11.3.2 pmap 263
- 11.3.3 pcalls 264
- 11.4 reduce/fold 264
- 11.5 小结 265
-
第5部分 宿主共生关系
- 第12章 Java.next 269
- 12.1 使用proxy动态生成
- 对象 270
- 12.2 Clojure gen-class和
- GUI程序设计 277
- 12.2.1 命名空间作为类的
- 规范 277
- 12.2.2 命名空间编译内幕 280
- 12.2.3 以Clojure探索用户界面
- 设计与开发 281
- 12.3 Clojure同Java数组的
- 关系 284
- 12.3.1 数组的类型:原生与
- 引用 284
- 12.3.2 数组可变性 286
- 12.3.3 那个不幸的命名
- 约定 286
- 12.3.4 多维数组 287
- 12.3.5 调用可变方法/构造
- 函数 288
- 12.4 所有Clojure函数都
- 实现…… 288
- 12.4.1 java.util.Comparator 288
- 12.4.2 java.lang.Runnable 289
- 12.4.3 java.util.concurrent.
- Callable 290
- 12.5 在Java API里使用
- Clojure数据结构 290
- 12.5.1 java.util.List 291
- 12.5.2 java.lang.Comparable 291
- 12.5.3 java.util.RandomAccess 292
- 12.5.4 java.util.Collection 292
- 12.5.5 java.util.Set 293
- 12.6 definterface 293
- 12.7 慎用异常 295
- 12.7.1 一点异常的背景 296
- 12.7.2 运行时异常vs.编译时
- 异常 296
- 12.7.3 处理异常 298
- 12.7.4 定制异常 299
- 12.8 小结 300
- 第13章 ClojureScript 301
- 13.1 实现VS接口 302
- 13.2 编译器内部:分析和
- 发布 305
- 13.2.1 编译步骤 305
- 13.2.2 Web Audio 307
- 13.2.3 高级编译 311
- 13.2.4 生成extern.js文件 313
- 13.3 编译和运行 315
- 13.4 小结 319
- 第6部分 杂 项 考 量
- 第14章 面向数据编程 323
- 14.1 代码是代码,数据是
- 数据 323
- 14.1.1 严格的分界 324
- 14.1.2 ORMG 325
- 14.1.3 从数据中获取信息的
- 一般方式 326
- 14.1.4 PLOP 327
- 14.2 数据就是数据 327
- 14.2.1 值的好处 328
- 14.2.2 标签符号 332
- 14.3 数据就是代码 335
- 14.3.1 数据可编程引擎 335
- 14.3.2 可编程数据引擎的
- 例子 336
- 14.3.3 例子:简单的事件
- 来源 337
- 14.4 代码就是数据,也是
- 代码 345
- 14.4.1 哈特的发现和
- 同像性 346
- 14.4.2 Clojure代码就是
- 数据 346
- 14.4.3 规范括号 346
- 14.5 小节 349
- 第15章 性能 351
- 15.1 类型提示 352
- 15.1.1 类型修饰的优势 352
- 15.1.2 类型提示实参和
- 返回值 352
- 15.1.3 类型提示对象 354
- 15.2 暂态(transient) 354
- 15.2.1 短暂的垃圾 354
- 15.2.2 暂态在效率上与可变集合
- 相比较 355
- 15.3 分块序列 356
- 15.4 记忆 358
- 15.4.1 记忆再研究 359
- 15.4.2 记忆协议 359
- 15.4.3 面向抽象编程 361
- 15.5 理解强制转型
- (coercion) 361
- 15.5.1 使用原始类型long 362
- 15.5.2 使用原生double 364
- 15.5.3 使用自动提升精度 365
- 15.6 可缩小的 366
- 15.6.1 简单的精简集合的
- 例子 366
- 15.6.2 派生第一个reducse函数
- 变种 367
- 15.6.3 更多的可还原函数的
- 转换器 369
- 15.6.4 reducible转换器 371
- 15.6.5 reducible的性能 372
- 15.6.6 reducible的缺陷 372
- 15.6.7 整合reducible到Clojure
- reduce 373
- 15.6.8 fold函数:并行的
- reduce 374
- 15.7 小结 377
- 第16章 思考程序 378
- 16.1 搜索问题 378
- 16.2 统一思考数据 383
- 16.2.1 潜在的平等性或
- 满足性 384
- 16.2.2 替换 387
- 16.2.3 一致性 388
- 16.3 关于core.logic 390
- 16.3.1 都是关于一致性 390
- 16.3.2 关系型 391
- 16.3.3 子目标 394
- 16.4 约束 397
- 16.4.1 约束编程介绍 397
- 16.4.2 通过有限域限制
- 绑定 399
- 16.4.3 利用有限域解决数独
- 问题 400
- 16.5 小结 403
- 第17章 Clojure改变我们的
- 思考方式 405
- 17.1 DSL 406
- 17.1.1 无所不在的DSL 406
- 17.1.2 实现类似SQL的DSL用于
- 生成查询 408
- 17.1.3 Clojure方式DSL的
- 注记 413
- 17.2 测试 413
- 17.2.1 一些有用的技术 414
- 17.2.2 契约式程序设计 416
- 17.3 缺乏设计模式 417
- 17.4 错误处理和调试 426
- 17.4.1 错误处理 426
- 17.4.2 调试 429
- 17.5 珍重 433
- 附录 资源 434
- Miscellaneous resources 434
- Online resources 440