書籍簡(jiǎn)介:
函數(shù)式編程將改變你思考代碼的方式!利用FP技術(shù),C#開(kāi)發(fā)人員可極大地提升狀態(tài)管理、并發(fā)處理和事件處理能力,并更好地長(zhǎng)期維護(hù)代碼。C#提供了靈活性,使你能充分利用函數(shù)式技術(shù)的優(yōu)勢(shì)?!禖#函數(shù)式編程 編寫更優(yōu)質(zhì)的C#代碼》從全新視角賦予你強(qiáng)大力量。 《C#函數(shù)式編程 編寫更優(yōu)質(zhì)的C#代碼》引導(dǎo)你在C#語(yǔ)言中使用函數(shù)式思想來(lái)解決現(xiàn)實(shí)問(wèn)題;首先介紹函數(shù)式編程的原理,分析如何借助C#語(yǔ)言特性實(shí)現(xiàn)函數(shù)式編程,然后在多個(gè)緊貼實(shí)用的示例的引導(dǎo)下,講述函數(shù)組合、數(shù)據(jù)流編程、不可變數(shù)據(jù)結(jié)構(gòu)以及使用LINQ構(gòu)建單子組合等主題。
作者簡(jiǎn)介:
Enrico Buonanno 畢業(yè)于哥倫比亞大學(xué)計(jì)算機(jī)科學(xué)系,是一名出色的開(kāi)發(fā)人員、架構(gòu)師和培訓(xùn)師,擁有15年的工作經(jīng)驗(yàn)。
出版日期:
2018年11月
章節(jié)目錄:
第Ⅰ部分 核心概念
第1章 介紹函數(shù)式編程 3
1.1 什么是函數(shù)式編程 4
1.1.1 函數(shù)作為第一類值 4
1.1.2 避免狀態(tài)突變 4
1.1.3 編寫具有強(qiáng)力保證的程序 5
1.2 C#的函數(shù)式語(yǔ)言 8
1.2.1 LINQ的函數(shù)式性質(zhì) 9
1.2.2 C# 6和C# 7中的函數(shù)式特性 10
1.2.3 未來(lái)的C#將更趨函數(shù)化 13
1.3 函數(shù)思維 13
1.3.1 映射函數(shù) 13
1.3.2 在C#中表示函數(shù) 14
1.4 高階函數(shù) 18
1.4.1 依賴于其他函數(shù)的函數(shù) 18
1.4.2 適配器函數(shù) 20
1.4.3 創(chuàng)建其他函數(shù)的函數(shù) 20
1.5 使用HOF避免重復(fù) 21
1.5.1 將安裝和拆卸封裝到HOF中 23
1.5.2 將using語(yǔ)句轉(zhuǎn)換為HOF 24
1.5.3 HOF的權(quán)衡 25
1.6 函數(shù)式編程的好處 27
練習(xí) 27
小結(jié) 28
第2章 為什么函數(shù)純潔性很重要 29
2.1 什么是函數(shù)的純潔性 29
2.1.1 純潔性和副作用 30
2.1.2 管理副作用的策略 31
2.2 純潔性和并發(fā)性 33
2.2.1 純函數(shù)可良好地并行化 34
2.2.2 并行化不純函數(shù) 35
2.2.3 避免狀態(tài)的突變 36
2.3 純潔性和可測(cè)性 38
2.3.1 實(shí)踐:一個(gè)驗(yàn)證場(chǎng)景 39
2.3.2 在測(cè)試中引入不純函數(shù) 40
2.3.3 為什么很難測(cè)試不純函數(shù) 42
2.3.4 參數(shù)化單元測(cè)試 43
2.3.5 避免標(biāo)頭接口 44
2.4 純潔性和計(jì)算的發(fā)展 47
練習(xí) 47
小結(jié) 48
第3章 設(shè)計(jì)函數(shù)簽名和類型 49
3.1 函數(shù)簽名設(shè)計(jì) 49
3.1.1 箭頭符號(hào) 50
3.1.2 簽名的信息量有多大 51
3.2 使用數(shù)據(jù)對(duì)象捕獲數(shù)據(jù) 52
3.2.1 原始類型通常不夠具體 53
3.2.2 使用自定義類型約束輸入 53
3.2.3 編寫“誠(chéng)實(shí)的”函數(shù) 55
3.2.4 使用元組和對(duì)象來(lái)組合值 56
3.3 使用Unit為數(shù)據(jù)缺失建模 58
3.3.1 為什么void不理想 58
3.3.2 使用Unit彌合Action和Func之間的差異 59
3.4 使用Option為數(shù)據(jù)可能缺失建模 61
3.4.1 你每天都在使用糟糕的API 61
3.4.2 Option類型的介紹 62
3.4.3 實(shí)現(xiàn)Option 65
3.4.4 通過(guò)使用Option而不是null來(lái)獲得健壯性 68
3.4.5 Option作為偏函數(shù)的自然結(jié)果類型 69
練習(xí) 73
小結(jié) 74
第4章 函數(shù)式編程中的模式 77
4.1 將函數(shù)應(yīng)用于結(jié)構(gòu)的內(nèi) 部值 77
4.1.1 將函數(shù)映射到序列上 77
4.1.2 將函數(shù)映射到Option 79
4.1.3 Option是如何提高抽象層級(jí)的 81
4.1.4 函子 82
4.2 使用ForEach執(zhí)行副作用 83
4.3 使用Bind來(lái)鏈接函數(shù) 85
4.3.1 將返回Option的函數(shù)結(jié)合起來(lái) 85
4.3.2 使用Bind平鋪嵌套列表 87
4.3.3 實(shí)際上,這被稱為單子 88
4.3.4 Return函數(shù) 88
4.3.5 函子和單子之間的關(guān)系 89
4.4 使用Where過(guò)濾值 90
4.5 使用Bind結(jié)合Option和IEnumerable 91
4.6 在不同抽象層級(jí)上編碼 92
4.6.1 常規(guī)值與高級(jí)值 93
4.6.2 跨越抽象層級(jí) 94
4.6.3 重新審視Map與Bind 95
4.6.4 在正確的抽象層級(jí)上
工作 96
練習(xí) 96
小結(jié) 97
第5章 使用函數(shù)組合設(shè)計(jì)程序 99
5.1 函數(shù)組合 99
5.1.1 復(fù)習(xí)函數(shù)組合 100
5.1.2 方法鏈 101
5.1.3 高級(jí)值界域中的組合 101
5.2 從數(shù)據(jù)流的角度進(jìn)行 思考 102
5.2.1 使用LINQ的可組合
API 102
5.2.2 編寫可組合性更好的函數(shù) 103
5.3 工作流編程 105
5.3.1 關(guān)于驗(yàn)證的一個(gè)簡(jiǎn)單
工作流 106
5.3.2 以數(shù)據(jù)流的思想進(jìn)行重構(gòu) 107
5.3.3 組合帶來(lái)了更大的靈活性 108
5.4 介紹函數(shù)式領(lǐng)域建模 109
5.5 端到端的服務(wù)器端 工作流 110
5.5.1 表達(dá)式與語(yǔ)句 112
5.5.2 聲明式與命令式 112
5.5.3 函數(shù)式分層 113
練習(xí) 115
小結(jié) 115
第Ⅱ部分 函數(shù)式風(fēng)格
第6章 函數(shù)式錯(cuò)誤處理 119
6.1 表示輸出的更安全方式 120
6.1.1 使用Either捕獲錯(cuò)誤細(xì)節(jié) 120
6.1.2 處理Either的核心函數(shù) 123
6.1.3 比較Option和Either 124
6.2 鏈接操作可能失敗 125
6.3 驗(yàn)證:Either的一個(gè)完美用例 127
6.3.1 為錯(cuò)誤選擇合適的表示法 128
6.3.2 定義一個(gè)基于Either的API 129
6.3.3 添加驗(yàn)證邏輯 130
6.4 將輸出提供給客戶端應(yīng)用程序 131
6.4.1 公開(kāi)一個(gè)類似Option的接口 132
6.4.2 公開(kāi)一個(gè)類似Either的接口 134
6.4.3 返回一個(gè)DTO結(jié)果 134
6.5 Either的變體 136
6.5.1 在不同的錯(cuò)誤表示之間進(jìn)行改變 136
6.5.2 Either的特定版本 137
6.5.3 重構(gòu)Validation和Exceptional 138
6.5.4 保留異常 141
練習(xí) 142
小結(jié) 142
第7章 用函數(shù)構(gòu)造一個(gè)應(yīng)用程序 145
7.1 偏函數(shù)應(yīng)用:逐個(gè)提供參數(shù) 146
7.1.1 手動(dòng)啟用偏函數(shù)應(yīng)用 147
7.1.2 歸納偏函數(shù)應(yīng)用 148
7.1.3 參數(shù)的順序問(wèn)題 150
7.2 克服方法解析的怪癖 150
7.3 柯里化函數(shù):優(yōu)化偏函數(shù)應(yīng)用 152
7.4 創(chuàng)建一個(gè)友好的偏函數(shù)應(yīng)用API 155
7.4.1 可文檔化的類型 156
7.4.2 具化數(shù)據(jù)訪問(wèn)函數(shù) 157
7.5 應(yīng)用程序的模塊化及
組合 159
7.5.1 OOP中的模塊化 160
7.5.2 FP中的模塊化 162
7.5.3 比較兩種方法 164
7.5.4 組合應(yīng)用程序 165
7.6 將列表壓縮為單個(gè)值 166
7.6.1 LINQ的Aggregate方法 166
7.6.2 聚合驗(yàn)證結(jié)果 168
7.6.3 收獲驗(yàn)證錯(cuò)誤 169
練習(xí) 170
小結(jié) 171
第8章 有效地處理多參函數(shù) 173
8.1 高級(jí)界域中的函數(shù)應(yīng)用程序 174
8.1.1 理解應(yīng)用式 176
8.1.2 提升函數(shù) 177
8.1.3 介紹基于屬性的測(cè)試 179
8.2 函子、應(yīng)用式、單子 181
8.3 單子定律 182
8.3.1 右恒等元 183
8.3.2 左恒等元 183
8.3.3 結(jié)合律 184
8.3.4 對(duì)多參函數(shù)使用Bind 185
8.4 通過(guò)對(duì)任何單子使用LINQ來(lái)提高可讀性 186
8.4.1 對(duì)任意函子使用LINQ 186
8.4.2 對(duì)任意單子使用LINQ 188
8.4.3 let、where及其他LINQ子句 191
8.5 何時(shí)使用Bind或Apply 192
8.5.1 具有智能構(gòu)造函數(shù)的驗(yàn)證 192
8.5.2 使用應(yīng)用式流來(lái)收集錯(cuò)誤 194
8.5.3 使用單子流來(lái)快速失敗 195
練習(xí) 196
小結(jié) 196
第9章 關(guān)于數(shù)據(jù)的函數(shù)式思考 199
9.1 狀態(tài)突變的陷阱 200
9.2 理解狀態(tài)、標(biāo)識(shí)及變化 202
9.2.1 有些事物永遠(yuǎn)不會(huì)變化 203
9.2.2 表示非突變的變化 205
9.3 強(qiáng)制不可變性 207
9.3.1 永遠(yuǎn)不可變 209
9.3.2 無(wú)樣板代碼的拷貝方法的可行性 210
9.3.3 利用F#處理數(shù)據(jù)類型 212
9.3.4 比較不變性的策略:一場(chǎng)丑陋的比賽 213
9.4 函數(shù)式數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)介 214
9.4.1 經(jīng)典的函數(shù)式鏈表 215
9.4.2 二叉樹(shù) 219
練習(xí) 223
小結(jié) 224
第10章 事件溯源:持久化的函數(shù) 式方法 225
10.1 關(guān)于數(shù)據(jù)存儲(chǔ)的函數(shù)式思考 226
10.1.1 為什么數(shù)據(jù)存儲(chǔ)只能追加 226
10.1.2 放松,并忘卻存儲(chǔ)狀態(tài) 227
10.2 事件溯源的基礎(chǔ)知識(shí) 228
10.2.1 表示事件 228
10.2.2 持久化事件 229
10.2.3 表示狀態(tài) 230
10.2.4 一個(gè)模式匹配的插曲 231
10.2.5 表示狀態(tài)轉(zhuǎn)換 234
10.2.6 從過(guò)去的事件中重建當(dāng)前狀態(tài) 235
10.3 事件溯源系統(tǒng)的架構(gòu) 236
10.3.1 處理命令 237
10.3.2 處理事件 240
10.3.3 添加驗(yàn)證 241
10.3.4 根據(jù)事件創(chuàng)建數(shù)據(jù)的視圖 243
10.4 比較不可變存儲(chǔ)的不同方法 246
10.4.1 Datomic與
Event Store 247
10.4.2 你的領(lǐng)域是否受事件驅(qū)動(dòng)? 247
小結(jié) 248
第Ⅲ部分 高級(jí)技術(shù)
第11章 惰性計(jì)算、延續(xù)以及單子組合之美 251
11.1 惰性的優(yōu)點(diǎn) 251
11.1.1 用于處理Option的惰性API 252
11.1.2 組合惰性計(jì)算 254
11.2 使用Try進(jìn)行異常處理 256
11.2.1 表示可能失敗的計(jì)算 257
11.2.2 從JSON對(duì)象中安全地提取信息 257
11.2.3 組合可能失敗的計(jì)算 259
11.2.4 單子組合:是什么意思呢? 260
11.3 為數(shù)據(jù)庫(kù)訪問(wèn)創(chuàng)建中間件管道 261
11.3.1 組合執(zhí)行安裝/拆卸的函數(shù) 261
11.3.2 逃離厄運(yùn)金字塔的秘方 263
11.3.3 捕獲中間件函數(shù)的本質(zhì) 263
11.3.4 實(shí)現(xiàn)中間件的查詢模式 265
11.3.5 添加計(jì)時(shí)操作的中間件 268
11.3.6 添加管理數(shù)據(jù)庫(kù)事務(wù)的中間件 269
小結(jié) 271
第12章 有狀態(tài)的程序和計(jì)算 273
12.1 管理狀態(tài)的程序 274
12.1.1 維護(hù)所檢索資源的緩存 275
12.1.2 重構(gòu)可測(cè)試性和錯(cuò)誤處理 277
12.1.3 有狀態(tài)的計(jì)算 278
12.2 一種用于生成隨機(jī)數(shù)據(jù)的語(yǔ)言 279
12.2.1 生成隨機(jī)整數(shù) 280
12.2.2 生成其他基元 281
12.2.3 生成復(fù)雜的結(jié)構(gòu) 282
12.3 有狀態(tài)計(jì)算的通用模式 284
小結(jié) 287
第13章 使用異步計(jì)算 289
13.1 異步計(jì)算 290
13.1.1 對(duì)異步的需要 290
13.1.2 用Task表示異步操作 291
13.1.3 Task作為一個(gè)將來(lái)值的容器 292
13.1.4 處理失敗 294
13.1.5 一個(gè)用于貨幣轉(zhuǎn)換的HTTP API 296
13.1.6 如果失敗,請(qǐng)?jiān)僭噹状?297
13.1.7 并行運(yùn)行異步操作 297
13.2 遍歷:處理高級(jí)值列表 299
13.2.1 使用單子的Traverse來(lái)驗(yàn)證值列表 301
13.2.2 使用應(yīng)用式Traverse來(lái)收集驗(yàn)證錯(cuò)誤 302
13.2.3 將多個(gè)驗(yàn)證器應(yīng)用于單個(gè)值 304
13.2.4 將Traverse與Task一起使用以等待多個(gè)結(jié)果 305
13.2.5 為單值結(jié)構(gòu)定義Traverse 306
13.3 結(jié)合異步和驗(yàn)證(或其他任何兩個(gè)單子效果) 308
13.3.1 堆疊單子的問(wèn)題 308
13.3.2 減少效果的數(shù)量 310
13.3.3 具有一個(gè)單子堆疊的LINQ表達(dá)式 311
小結(jié) 312
第14章 數(shù)據(jù)流和Reactive Extensions 315
14.1 用IObservable表示數(shù)據(jù)流 316
14.1.1 時(shí)間上的一個(gè)序列的值 316
14.1.2 訂閱IObservable 317
14.2 創(chuàng)建IObservable 318
14.2.1 創(chuàng)建一個(gè)定時(shí)器 319
14.2.2 使用Subject來(lái)告知IObservable應(yīng)何時(shí)發(fā)出信號(hào) 320
14.2.3 從基于回調(diào)的訂閱中創(chuàng)建IObservable 320
14.2.4 由更簡(jiǎn)單的結(jié)構(gòu)創(chuàng)建IObservable 321
14.3 轉(zhuǎn)換和結(jié)合數(shù)據(jù)流 323
14.3.1 流的轉(zhuǎn)換 323
14.3.2 結(jié)合和劃分流 325
14.3.3 使用IObservable進(jìn)行錯(cuò)誤處理 327
14.3.4 融會(huì)貫通 329
14.4 實(shí)現(xiàn)貫穿多個(gè)事件的邏輯 330
14.4.1 檢測(cè)按鍵順序 330
14.4.2 對(duì)事件源作出反應(yīng) 333
14.4.3 通知賬戶何時(shí)透支 335
14.5 應(yīng)該何時(shí)使用IObservable? 337
小結(jié) 338
第15章 并發(fā)消息傳遞 339
15.1 對(duì)共享可變狀態(tài)的需要 339
15.2 理解并發(fā)消息傳遞 341
15.2.1 在C#中實(shí)現(xiàn)代理 343
15.2.2 開(kāi)始使用代理 344
15.2.3 使用代理處理并發(fā)請(qǐng)求 346
15.2.4 代理與角色 349
15.3 “函數(shù)式API”與“基于代理的實(shí)現(xiàn)” 350
15.3.1 代理作為實(shí)現(xiàn)細(xì)節(jié) 351
15.3.2 將代理隱藏于常規(guī)API的背后 352
15.4 LOB應(yīng)用程序中的并發(fā)消息傳遞 353
15.4.1 使用代理來(lái)同步對(duì)賬戶數(shù)據(jù)的訪問(wèn) 354
15.4.2 保管賬戶的注冊(cè)表 356
15.4.3 代理不是一個(gè)對(duì)象 357
15.4.4 融會(huì)貫通 359
小結(jié) 361
結(jié)束語(yǔ):接下來(lái)呢? 363
封面圖: