描述
开 本: 128开纸 张: 胶版纸包 装: 平装-胶订是否套装: 否国际标准书号ISBN: 9787302510550
内容简介
函数式编程将改变你思考代码的方式!利用FP技术,C#开发人员可极大地提升状态管理、并发处理和事件处理能力,并更好地长期维护代码。C#提供了灵活性,使你能充分利用函数式技术的优势。《C#函数式编程 编写更优质的C#代码》从全新视角赋予你强大力量。
《C#函数式编程 编写更优质的C#代码》引导你在C#语言中使用函数式思想来解决现实问题;首先介绍函数式编程的原理,分析如何借助C#语言特性实现函数式编程,然后在多个紧贴实用的示例的引导下,讲述函数组合、数据流编程、不可变数据结构以及使用LINQ构建单子组合等主题。
目 录
第Ⅰ部分核心概念
章介绍函数式编程3
1.1什么是函数式编程4
1.1.1函数作为类值4
1.1.2避免状态突变4
1.1.3编写具有强力保证的程序5
1.2C#的函数式语言8
1.2.1LINQ的函数式性质9
1.2.2C#6和C#7中的函数式特性10
1.2.3未来的C#将更趋函数化13
1.3函数思维13
1.3.1映射函数13
1.3.2在C#中表示函数14
1.4高阶函数18
1.4.1依赖于其他函数的函数18
1.4.2适配器函数20
1.4.3创建其他函数的函数20
1.5使用HOF避免重复21
1.5.1将安装和拆卸封装到HOF中23
1.5.2将using语句转换为HOF24
1.5.3HOF的权衡25
1.6函数式编程的好处27
练习27
小结28
第2章为什么函数纯洁性很重要29
2.1什么是函数的纯洁性29
2.1.1纯洁性和副作用30
2.1.2管理副作用的策略31
2.2纯洁性和并发性33
2.2.1纯函数可良好地并行化34
2.2.2并行化不纯函数35
2.2.3避免状态的突变36
2.3纯洁性和可测性38
2.3.1实践:一个验证场景39
2.3.2在测试中引入不纯函数40
2.3.3为什么很难测试不纯函数42
2.3.4参数化单元测试43
2.3.5避免标头接口44
2.4纯洁性和计算的发展47
练习47
小结48
第3章设计函数和类型49
3.1函数设计49
3.1.1箭头符号50
3.1.2的信息量有多大51
3.2使用数据对象捕获数据52
3.2.1原始类型通常不够具体53
3.2.2使用自定义类型约束输入53
3.2.3编写“诚实的”函数55
3.2.4使用元组和对象来组合值56
3.3使用Unit为数据缺失建模58
3.3.1为什么void不理想58
3.3.2使用Unit弥合Action和Func之间的差异59
3.4使用Option为数据可能缺失建模61
3.4.1你每天都在使用糟糕的API61
3.4.2Option类型的介绍62
3.4.3实现Option65
3.4.4通过使用Option而不是null来获得健壮性68
3.4.5Option作为偏函数的自然结果类型69
练习73
小结74
第4章函数式编程中的模式77
4.1将函数应用于结构的内部值77
4.1.1将函数映射到序列上77
4.1.2将函数映射到Option79
4.1.3Option是如何提高抽象层级的81
4.1.4函子82
4.2使用ForEach执行副作用83
4.3使用Bind来链接函数85
4.3.1将返回Option的函数结合起来85
4.3.2使用Bind平铺嵌套列表87
4.3.3实际上,这被称为单子88
4.3.4Return函数88
4.3.5函子和单子之间的关系89
4.4使用Where过滤值90
4.5使用Bind结合Option和IEnumerable91
4.6在不同抽象层级上编码92
4.6.1常规值与高级值93
4.6.2跨越抽象层级94
4.6.3重新审视Map与Bind95
4.6.4在正确的抽象层级上
工作96
练习96
小结97
第5章使用函数组合设计程序99
5.1函数组合99
5.1.1复习函数组合100
5.1.2方法链101
5.1.3高级值界域中的组合101
5.2从数据流的角度进行思考102
5.2.1使用LINQ的可组合
API102
5.2.2编写可组合性更好的函数103
5.3工作流编程105
5.3.1关于验证的一个简单
工作流106
5.3.2以数据流的思想进行重构107
5.3.3组合带来了更大的灵活性108
5.4介绍函数式领域建模109
5.5端到端的服务器端工作流110
5.5.1表达式与语句112
5.5.2声明式与命令式112
5.5.3函数式分层113
练习115
小结115
第Ⅱ部分函数式风格
第6章函数式错误处理119
6.1表示输出的更安全方式120
6.1.1使用Either捕获错误细节120
6.1.2处理Either的核心函数123
6.1.3比较Option和Either124
6.2链接操作可能失败125
6.3验证:Either的一个用例127
6.3.1为错误选择合适的表示法128
6.3.2定义一个基于Either的API129
6.3.3添加验证逻辑130
6.4将输出提供给客户端应用程序131
6.4.1公开一个类似Option的接口132
6.4.2公开一个类似Either的接口134
6.4.3返回一个DTO结果134
6.5Either的变体136
6.5.1在不同的错误表示之间进行改变136
6.5.2Either的特定版本137
6.5.3重构Validation和Exceptional138
6.5.4保留异常141
练习142
小结142
第7章用函数构造一个应用程序145
7.1偏函数应用:逐个提供参数146
7.1.1手动启用偏函数应用147
7.1.2归纳偏函数应用148
7.1.3参数的顺序问题150
7.2克服方法解析的怪癖150
7.3柯里化函数:优化偏函数应用152
7.4创建一个友好的偏函数应用API155
7.4.1可文档化的类型156
7.4.2具化数据访问函数157
7.5应用程序的模块化及
组合159
7.5.1OOP中的模块化160
7.5.2FP中的模块化162
7.5.3比较两种方法164
7.5.4组合应用程序165
7.6将列表压缩为单个值166
7.6.1LINQ的Aggregate方法166
7.6.2聚合验证结果168
7.6.3收获验证错误169
练习170
小结171
第8章有效地处理多参函数173
8.1高级界域中的函数应用程序174
8.1.1理解应用式176
8.1.2提升函数177
8.1.3介绍基于属性的测试179
8.2函子、应用式、单子181
8.3单子定律182
8.3.1右恒等元183
8.3.2左恒等元183
8.3.3结合律184
8.3.4对多参函数使用Bind185
8.4通过对任何单子使用LINQ来提高可读性186
8.4.1对任意函子使用LINQ186
8.4.2对任意单子使用LINQ188
8.4.3let、where及其他LINQ子句191
8.5何时使用Bind或Apply192
8.5.1具有智能构造函数的验证192
8.5.2使用应用式流来收集错误194
8.5.3使用单子流来快速失败195
练习196
小结196
第9章关于数据的函数式思考199
9.1状态突变的陷阱200
9.2理解状态、标识及变化202
9.2.1有些事物永远不会变化203
9.2.2表示非突变的变化205
9.3强制不可变性207
9.3.1永远不可变209
9.3.2无样板代码的拷贝方法的可行性210
9.3.3利用F#处理数据类型212
9.3.4比较不变性的策略:一场丑陋的比赛213
9.4函数式数据结构简介214
9.4.1经典的函数式链表215
9.4.2二叉树219
练习223
小结224
0章事件溯源:持久化的函数式方法225
10.1关于数据存储的函数式思考226
10.1.1为什么数据存储只能追加226
10.1.2放松,并忘却存储状态227
10.2事件溯源的基础知识228
10.2.1表示事件228
10.2.2持久化事件229
10.2.3表示状态230
10.2.4一个模式匹配的插曲231
10.2.5表示状态转换234
10.2.6从过去的事件中重建当前状态235
10.3事件溯源系统的架构236
10.3.1处理命令237
10.3.2处理事件240
10.3.3添加验证241
10.3.4根据事件创建数据的视图243
10.4比较不可变存储的不同方法246
10.4.1Datomic与
EventStore247
10.4.2你的领域是否受事件驱动?247
小结248
第Ⅲ部分高级技术
1章惰性计算、延续以及单子组合之美251
11.1惰性的优点251
11.1.1用于处理Option的惰性API252
11.1.2组合惰性计算254
11.2使用Try进行异常处理256
11.2.1表示可能失败的计算257
11.2.2从JSON对象中安全地提取信息257
11.2.3组合可能失败的计算259
11.2.4单子组合:是什么意思呢?260
11.3为数据库访问创建中间件管道261
11.3.1组合执行安装/拆卸的函数261
11.3.2逃离厄运金字塔的秘方263
11.3.3捕获中间件函数的本质263
11.3.4实现中间件的查询模式265
11.3.5添加计时操作的中间件268
11.3.6添加管理数据库事务的中间件269
小结271
2章有状态的程序和计算273
12.1管理状态的程序274
12.1.1维护所检索资源的缓存275
12.1.2重构可测试性和错误处理277
12.1.3有状态的计算278
12.2一种用于生成数据的语言279
12.2.1生成整数280
12.2.2生成其他基元281
12.2.3生成复杂的结构282
12.3有状态计算的通用模式284
小结287
3章使用异步计算289
13.1异步计算290
13.1.1对异步的需要290
13.1.2用Task表示异步操作291
13.1.3Task作为一个将来值的容器292
13.1.4处理失败294
13.1.5一个用于货币转换的API296
13.1.6如果失败,请再试几次297
13.1.7并行运行异步操作297
13.2遍历:处理高级值列表299
13.2.1使用单子的Traverse来验证值列表301
13.2.2使用应用式Traverse来收集验证错误302
13.2.3将多个验证器应用于单个值304
13.2.4将Traverse与Task一起使用以等待多个结果305
13.2.5为单值结构定义Traverse306
13.3结合异步和验证(或其他任何两个单子效果)308
13.3.1堆叠单子的问题308
13.3.2减少效果的数量310
13.3.3具有一个单子堆叠的LINQ表达式311
小结312
4章数据流和ReactiveExtensions315
14.1用IObservable表示数据流316
14.1.1时间上的一个序列的值316
14.1.2订阅IObservable317
14.2创建IObservable318
14.2.1创建一个定时器319
14.2.2使用Subject来告知IObservable应何时发出信号320
14.2.3从基于回调的订阅中创建IObservable320
14.2.4由更简单的结构创建IObservable321
14.3转换和结合数据流323
14.3.1流的转换323
14.3.2结合和划分流325
14.3.3使用IObservable进行错误处理327
14.3.4融会贯通329
14.4实现贯穿多个事件的逻辑330
14.4.1检测按键顺序330
14.4.2对事件源作出反应333
14.4.3通知账户何时透支335
14.5应该何时使用IObservable?337
小结338
5章并发消息传递339
15.1对共享可变状态的需要339
15.2理解并发消息传递341
15.2.1在C#中实现代理343
15.2.2开始使用代理344
15.2.3使用代理处理并发请求346
15.2.4代理与角色349
15.3“函数式API”与“基于代理的实现”350
15.3.1代理作为实现细节351
15.3.2将代理隐藏于常规API的背后352
15.4LOB应用程序中的并发消息传递353
15.4.1使用代理来同步对账户数据的访问354
15.4.2保管账户的注册表356
15.4.3代理不是一个对象357
15.4.4融会贯通359
小结361
结束语:接下来呢?363
章介绍函数式编程3
1.1什么是函数式编程4
1.1.1函数作为类值4
1.1.2避免状态突变4
1.1.3编写具有强力保证的程序5
1.2C#的函数式语言8
1.2.1LINQ的函数式性质9
1.2.2C#6和C#7中的函数式特性10
1.2.3未来的C#将更趋函数化13
1.3函数思维13
1.3.1映射函数13
1.3.2在C#中表示函数14
1.4高阶函数18
1.4.1依赖于其他函数的函数18
1.4.2适配器函数20
1.4.3创建其他函数的函数20
1.5使用HOF避免重复21
1.5.1将安装和拆卸封装到HOF中23
1.5.2将using语句转换为HOF24
1.5.3HOF的权衡25
1.6函数式编程的好处27
练习27
小结28
第2章为什么函数纯洁性很重要29
2.1什么是函数的纯洁性29
2.1.1纯洁性和副作用30
2.1.2管理副作用的策略31
2.2纯洁性和并发性33
2.2.1纯函数可良好地并行化34
2.2.2并行化不纯函数35
2.2.3避免状态的突变36
2.3纯洁性和可测性38
2.3.1实践:一个验证场景39
2.3.2在测试中引入不纯函数40
2.3.3为什么很难测试不纯函数42
2.3.4参数化单元测试43
2.3.5避免标头接口44
2.4纯洁性和计算的发展47
练习47
小结48
第3章设计函数和类型49
3.1函数设计49
3.1.1箭头符号50
3.1.2的信息量有多大51
3.2使用数据对象捕获数据52
3.2.1原始类型通常不够具体53
3.2.2使用自定义类型约束输入53
3.2.3编写“诚实的”函数55
3.2.4使用元组和对象来组合值56
3.3使用Unit为数据缺失建模58
3.3.1为什么void不理想58
3.3.2使用Unit弥合Action和Func之间的差异59
3.4使用Option为数据可能缺失建模61
3.4.1你每天都在使用糟糕的API61
3.4.2Option类型的介绍62
3.4.3实现Option65
3.4.4通过使用Option而不是null来获得健壮性68
3.4.5Option作为偏函数的自然结果类型69
练习73
小结74
第4章函数式编程中的模式77
4.1将函数应用于结构的内部值77
4.1.1将函数映射到序列上77
4.1.2将函数映射到Option79
4.1.3Option是如何提高抽象层级的81
4.1.4函子82
4.2使用ForEach执行副作用83
4.3使用Bind来链接函数85
4.3.1将返回Option的函数结合起来85
4.3.2使用Bind平铺嵌套列表87
4.3.3实际上,这被称为单子88
4.3.4Return函数88
4.3.5函子和单子之间的关系89
4.4使用Where过滤值90
4.5使用Bind结合Option和IEnumerable91
4.6在不同抽象层级上编码92
4.6.1常规值与高级值93
4.6.2跨越抽象层级94
4.6.3重新审视Map与Bind95
4.6.4在正确的抽象层级上
工作96
练习96
小结97
第5章使用函数组合设计程序99
5.1函数组合99
5.1.1复习函数组合100
5.1.2方法链101
5.1.3高级值界域中的组合101
5.2从数据流的角度进行思考102
5.2.1使用LINQ的可组合
API102
5.2.2编写可组合性更好的函数103
5.3工作流编程105
5.3.1关于验证的一个简单
工作流106
5.3.2以数据流的思想进行重构107
5.3.3组合带来了更大的灵活性108
5.4介绍函数式领域建模109
5.5端到端的服务器端工作流110
5.5.1表达式与语句112
5.5.2声明式与命令式112
5.5.3函数式分层113
练习115
小结115
第Ⅱ部分函数式风格
第6章函数式错误处理119
6.1表示输出的更安全方式120
6.1.1使用Either捕获错误细节120
6.1.2处理Either的核心函数123
6.1.3比较Option和Either124
6.2链接操作可能失败125
6.3验证:Either的一个用例127
6.3.1为错误选择合适的表示法128
6.3.2定义一个基于Either的API129
6.3.3添加验证逻辑130
6.4将输出提供给客户端应用程序131
6.4.1公开一个类似Option的接口132
6.4.2公开一个类似Either的接口134
6.4.3返回一个DTO结果134
6.5Either的变体136
6.5.1在不同的错误表示之间进行改变136
6.5.2Either的特定版本137
6.5.3重构Validation和Exceptional138
6.5.4保留异常141
练习142
小结142
第7章用函数构造一个应用程序145
7.1偏函数应用:逐个提供参数146
7.1.1手动启用偏函数应用147
7.1.2归纳偏函数应用148
7.1.3参数的顺序问题150
7.2克服方法解析的怪癖150
7.3柯里化函数:优化偏函数应用152
7.4创建一个友好的偏函数应用API155
7.4.1可文档化的类型156
7.4.2具化数据访问函数157
7.5应用程序的模块化及
组合159
7.5.1OOP中的模块化160
7.5.2FP中的模块化162
7.5.3比较两种方法164
7.5.4组合应用程序165
7.6将列表压缩为单个值166
7.6.1LINQ的Aggregate方法166
7.6.2聚合验证结果168
7.6.3收获验证错误169
练习170
小结171
第8章有效地处理多参函数173
8.1高级界域中的函数应用程序174
8.1.1理解应用式176
8.1.2提升函数177
8.1.3介绍基于属性的测试179
8.2函子、应用式、单子181
8.3单子定律182
8.3.1右恒等元183
8.3.2左恒等元183
8.3.3结合律184
8.3.4对多参函数使用Bind185
8.4通过对任何单子使用LINQ来提高可读性186
8.4.1对任意函子使用LINQ186
8.4.2对任意单子使用LINQ188
8.4.3let、where及其他LINQ子句191
8.5何时使用Bind或Apply192
8.5.1具有智能构造函数的验证192
8.5.2使用应用式流来收集错误194
8.5.3使用单子流来快速失败195
练习196
小结196
第9章关于数据的函数式思考199
9.1状态突变的陷阱200
9.2理解状态、标识及变化202
9.2.1有些事物永远不会变化203
9.2.2表示非突变的变化205
9.3强制不可变性207
9.3.1永远不可变209
9.3.2无样板代码的拷贝方法的可行性210
9.3.3利用F#处理数据类型212
9.3.4比较不变性的策略:一场丑陋的比赛213
9.4函数式数据结构简介214
9.4.1经典的函数式链表215
9.4.2二叉树219
练习223
小结224
0章事件溯源:持久化的函数式方法225
10.1关于数据存储的函数式思考226
10.1.1为什么数据存储只能追加226
10.1.2放松,并忘却存储状态227
10.2事件溯源的基础知识228
10.2.1表示事件228
10.2.2持久化事件229
10.2.3表示状态230
10.2.4一个模式匹配的插曲231
10.2.5表示状态转换234
10.2.6从过去的事件中重建当前状态235
10.3事件溯源系统的架构236
10.3.1处理命令237
10.3.2处理事件240
10.3.3添加验证241
10.3.4根据事件创建数据的视图243
10.4比较不可变存储的不同方法246
10.4.1Datomic与
EventStore247
10.4.2你的领域是否受事件驱动?247
小结248
第Ⅲ部分高级技术
1章惰性计算、延续以及单子组合之美251
11.1惰性的优点251
11.1.1用于处理Option的惰性API252
11.1.2组合惰性计算254
11.2使用Try进行异常处理256
11.2.1表示可能失败的计算257
11.2.2从JSON对象中安全地提取信息257
11.2.3组合可能失败的计算259
11.2.4单子组合:是什么意思呢?260
11.3为数据库访问创建中间件管道261
11.3.1组合执行安装/拆卸的函数261
11.3.2逃离厄运金字塔的秘方263
11.3.3捕获中间件函数的本质263
11.3.4实现中间件的查询模式265
11.3.5添加计时操作的中间件268
11.3.6添加管理数据库事务的中间件269
小结271
2章有状态的程序和计算273
12.1管理状态的程序274
12.1.1维护所检索资源的缓存275
12.1.2重构可测试性和错误处理277
12.1.3有状态的计算278
12.2一种用于生成数据的语言279
12.2.1生成整数280
12.2.2生成其他基元281
12.2.3生成复杂的结构282
12.3有状态计算的通用模式284
小结287
3章使用异步计算289
13.1异步计算290
13.1.1对异步的需要290
13.1.2用Task表示异步操作291
13.1.3Task作为一个将来值的容器292
13.1.4处理失败294
13.1.5一个用于货币转换的API296
13.1.6如果失败,请再试几次297
13.1.7并行运行异步操作297
13.2遍历:处理高级值列表299
13.2.1使用单子的Traverse来验证值列表301
13.2.2使用应用式Traverse来收集验证错误302
13.2.3将多个验证器应用于单个值304
13.2.4将Traverse与Task一起使用以等待多个结果305
13.2.5为单值结构定义Traverse306
13.3结合异步和验证(或其他任何两个单子效果)308
13.3.1堆叠单子的问题308
13.3.2减少效果的数量310
13.3.3具有一个单子堆叠的LINQ表达式311
小结312
4章数据流和ReactiveExtensions315
14.1用IObservable表示数据流316
14.1.1时间上的一个序列的值316
14.1.2订阅IObservable317
14.2创建IObservable318
14.2.1创建一个定时器319
14.2.2使用Subject来告知IObservable应何时发出信号320
14.2.3从基于回调的订阅中创建IObservable320
14.2.4由更简单的结构创建IObservable321
14.3转换和结合数据流323
14.3.1流的转换323
14.3.2结合和划分流325
14.3.3使用IObservable进行错误处理327
14.3.4融会贯通329
14.4实现贯穿多个事件的逻辑330
14.4.1检测按键顺序330
14.4.2对事件源作出反应333
14.4.3通知账户何时透支335
14.5应该何时使用IObservable?337
小结338
5章并发消息传递339
15.1对共享可变状态的需要339
15.2理解并发消息传递341
15.2.1在C#中实现代理343
15.2.2开始使用代理344
15.2.3使用代理处理并发请求346
15.2.4代理与角色349
15.3“函数式API”与“基于代理的实现”350
15.3.1代理作为实现细节351
15.3.2将代理隐藏于常规API的背后352
15.4LOB应用程序中的并发消息传递353
15.4.1使用代理来同步对账户数据的访问354
15.4.2保管账户的注册表356
15.4.3代理不是一个对象357
15.4.4融会贯通359
小结361
结束语:接下来呢?363
评论
还没有评论。