Chapter 1. Introducing functional programming
覆盖first-class functions、避免mutation、strong guarantees、C#函数式能力、function representation、HOF去重与收益,以显式behavior和effect boundary入门。
学习目标
- 能解释first-class functions、immutability与strong guarantees如何改变dependency、state transition和reasoning boundary
- 能比较method group、delegate、lambda、adapter与function factory的binding/capture语义,复现同一behavior的不同表示
- 能设计setup/execute/teardown型higher-order function,区分消除duplication与隐藏control flow的边界
为什么Functional Programming先改变思考单位
Imperative code常把“做什么、按什么顺序、改了谁”写在同一块;functional style尝试把behavior当value,把data transition写成从input到output的mapping,把不可避免的I/O留给明确boundary。重点不是禁止class、loop或mutation,而是让reasoning所需信息尽量出现在signature和value flow里。
先预测:使用lambda是否就等于functional;LINQ query不修改source是否就保证整个program pure;把setup/teardown包进HOF是否永远更清楚;同一个capturing lambda多次执行是否必然给相同结果。答案都是否。
↡Function可以像其他value一样被赋值、作为argument传入、作为result返回并组成更大behavior。What is this thing called functional programming?
本书用三条可操作特征切入:functions as first-class values、avoiding state mutation、writing programs with strong guarantees。First-class让依赖behavior不必硬编码;immutable transformations让旧state仍可观察;strong guarantee让caller能依据explicit input推理result与failure,而不必先扫描global variables。
Mutation不是语法罪名,而是alias和ordering成本。List<T>.Sort()原地改变list,所有持有alias的code都观察到变化;OrderBy返回新的sequence view,source保持不变。后者仍可能deferred、capture或访问I/O,因此“non-mutating API”不自动等于pure。
var source = new[] { 3, 1, 2 };
var ordered = source.OrderBy(value => value).ToArray();
// source remains [3, 1, 2]; ordered is [1, 2, 3]切换first-class、mutation、immutable与guarantee
How functional a language is C#?
C#是multi-paradigm language。Delegates/lambdas把functions变成values,LINQ提供Map/Filter/Bind-like composition,generics表达container operations,C# 6/7又加入expression-bodied members、tuples、pattern等更适合value flow的syntax。但C#不会强制purity,也没有built-in algebraic data types或自动effect tracking。
因此functionality来自discipline和library design:immutable inputs、honest signatures、pure core、explicit effect shell。Modern C# records、nullable references与new patterns属于第二版及之后语境;本第一版正文保持C# 6/7边界,后续只作为versioned alternatives。
Thinking in functions
把function看作数学mapping并不要求所有business code都能写成公式,而是要求问:domain是什么、codomain是什么、哪些inputs未写出来、哪些outputs通过mutation或exception偷偷传递。C# method只有在转换到delegate/expression type后才作为value参与composition。
Func<Order, decimal> total = order => order.Lines.Sum(line => line.Price);
Func<decimal, string> format = value => value.ToString("C", culture);
Func<Order, string> display = order => format(total(order));切换method、lambda、adapter与factory
Higher-order functions
Higher-order function接收function、返回function,或两者兼有。Where依赖predicate,adapter把一个signature转换为另一个,factory通过capture生成specialized behavior。它让variation成为explicit argument,减少inheritance/config flags带来的隐形branch。
HOF也可能过度抽象:若传入functions数量太多、generic types难以读、control flow跨多层,reader只能在debugger里恢复执行顺序。判断标准是调用点是否更像domain sentence,effect/lifetime是否更明确。
↡接收或产生function value,从而抽象behavior variation、policy或lifecycle的function。Using HOFs to avoid duplication
典型重复不是业务action,而是数据库connection的open/close、transaction commit/rollback或lock acquire/release。HOF可以拥有setup和teardown,把差异action作为function传入。它必须通过using/try-finally保证normal与fault cleanup,并声明resource由谁拥有。
static T WithConnection<T>(Func<IDbConnection, T> use)
{
using var connection = OpenConnection();
connection.Open();
return use(connection);
}
var customer = WithConnection(db => LoadCustomer(db, id));把using变HOF的收益是lifecycle policy集中;代价是stack trace、async support、transaction boundary和multiple operations可能变复杂。Modern async resource需要separate async HOF/await using,不能让sync wrapper阻塞Task。
切换setup、execute、teardown与tradeoff
Benefits of functional programming
收益来自上述约束的组合:pure function容易test与parallelize;immutable value减少alias reasoning;composition让workflow按types连接;HOF集中policy;explicit outcomes减少exception/null surprise。它不是用更学术的词替换OOP,而是在适合的boundary降低可变状态与隐形依赖。
↡给定相同显式inputs时,可用value substitution替换function call而不改变program observable behavior的性质。本章回顾:Behavior、Data与Effect各有位置
- Functional style把behavior当value、state change当transformation、effect留给owner boundary。
- C#提供delegates、lambdas、LINQ和generics,但purity与immutability依赖设计纪律。
- Function-as-map迫使signature暴露domain、codomain与hidden dependency。
- HOF可抽象policy和lifecycle,必须保留control flow与resource ownership。
- Purity、immutability和composition共同带来testability、concurrency与maintenance收益。
练习
问题 1:一个lambda读取DateTime.Now但不写任何state,它pure吗?
问题 2:怎样判断resource HOF是否比重复using更好?
问题 3:First-class function最直接改善哪类dependency?
术语表
名词解释
本章出现的专业名词,用大白话再讲一遍。
- first-class behavior
- immutable transformation
- function-as-map model
- higher-order function
- substitution guarantee