Clojure 編程樂趣, 2/e (The Joy of Clojure, 2/e)
內容描述
這既不是一本Clojure初學指南,也不是一本Clojure的編程操作手冊。本書通過對Clojure詳盡地探究,講述函數式的程序設計方式,幫助讀者理解和體會Clojure編程的樂趣,進而開發出優美的軟件。
全書分為6個部分共17章。第1部分是基礎,包括第1~3章,從Clojure背後的思想開始,介紹了Clojure的基礎知識,並帶領讀者初步嘗試Clojure編程。第2部分是第4章和第5章,介紹了Clojure的各種數據類型。第3部分是第6章和第7章,介紹了函數式編程的特性。第4部分是第8章~11章,分別介紹了宏、組合數據域代碼、Clojure對Java的調用,以及並發編程等較為高級的話題。第5部分為第12章和第13章,探討了Clojure的性能問題及其帶給我們的思考。第6部分為第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使用promis e的時機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裡使用
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. Collect ion 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