HYDROGRAPHIC SURVEY · 水文志 · 1987—2026
上游
U P S T R E A M
你在 Kotlin 里写的 sealed class、Java 里的 Optional 与 record、TypeScript 里的判别联合、React 里「UI 是状态的纯函数」——这些让你觉得「真好用」的东西,没有一个是凭空发明的。它们都来自同一条河的上游:Haskell 与 ML 语系。
这本小书不劝你转行。它带你溯流而上,到源头看一遍原版:原版的代数数据类型、原版的模式匹配、原版的 Maybe、被过度神化的 Monad,以及只有源头才有的惰性求值、QuickCheck 与解析器组合子——然后带着思想顺流回家,把你手里的 Kotlin、Java、TS 写得更好。
STATION I · 河口 ESTUARY
出发之地
先把「为什么是 Haskell」讲清楚:一张特性溯源地图,和一段避免成功的历史。
STATION II · 干流 MAINSTREAM
语言的骨与形
六章过完语言核心:表达式、类型、ADT、fold、类型类、惰性——每一章都在给你的语言「认亲」。
02
GHCi 与函数:一切皆表达式
没有 return、没有语句,函数天生柯里化;$ 与 . 是怎么把括号消灭掉的。附一台真·惰性求值引擎驱动的浏览器 GHCi。
▸ 受限 GHCi 终端
03
读懂类型签名:多态与推断
a -> b 里藏着多少信息?参数化多态为什么比泛型「更硬」?Hindley-Milner 如何不用你写一个类型就推出全部——本章的推断台是照着 Algorithm W 真实现的。
▸ 类型推断台
04
ADT 与模式匹配:让非法状态无法表示
和类型 + 积类型 = 代数;sealed class 的原版长什么样;把「isLoading + hasError 布尔堆」重构成一眼看穿的 data,再让编译器替你检查漏网分支。
▸ 状态空间测量台
05
递归与 fold:一切循环的祖先
列表天生是递归的,所以循环天生是 fold;reduce、Stream.collect、sum、reverse 全是它的马甲。foldr 和 foldl 的括号方向,一步步展开给你看。
▸ fold 展开观测
06
类型类:开放世界的接口
interface 要求「生而实现」,类型类允许「事后补票」;Eq/Ord/Show/Num 的日常,deriving 的白嫖,以及编译器如何把约束变成一本悄悄传递的字典。
▸ 字典传递透视
07
惰性:无限列表与 thunk
Haskell 默认什么都不算,直到有人真的要;[1..] 为什么不炸、Sequence/Stream 抄走了什么、以及 thunk 到底长什么样——逐帧快照给你看。
▸ thunk 单步求值器
STATION III · 峡谷 GORGE
最湍急的一段:效应与 Monad
劝退发生地。我们不从范畴论进,从你写过一百遍的判空代码进——五章之后,Monad 只是个普通接口。
08
Maybe 与 Either:告别 null 与异常
十亿美元的错误在类型系统里是怎么被关起来的;Either 如何让错误路径成为「铁路的另一条轨」,短路而不失控。
▸ Either 铁路调度
09
Functor 与 Applicative:抽象的台阶
fmap 就是你熟悉的 map,只是「容器」二字被抽象掉了;Applicative 解决「函数也在盒子里」的尴尬。台阶搭好,Monad 只剩一步。
10
Monad 祛魅:do 只是语法糖
>>= 的类型一旦读懂,一切玄学蒸发;do 块喂给脱糖器,亲眼看它变回普通函数调用。顺便解释为什么「Monad 教程」是个梗。
▸ do 脱糖器
11
IO:纯语言怎么干脏活
main 的类型是 IO (),意味着「描述副作用」和「执行副作用」被劈开了;functional core, imperative shell 在这里是语言级强制——这是全书最值钱的一课。
12
Monad 巡礼:State、Reader、Writer
State 是 Redux reducer,Reader 是依赖注入,Writer 是结构化日志——你早就在用它们,只是没人告诉你名字。
STATION IV · 上游 UPSTREAM
独门手艺
只有源头才有的东西:性质代替用例、组合子代替正则、事务代替锁,以及给惰性付账的方法。
13
QuickCheck:让性质替你写测试
别再手编用例了——声明性质,机器造两百组输入轰它,失败后自动收缩出最小反例。这项 2000 年的发明,今天在 jqwik/Hypothesis/fast-check 里等你。
▸ 属性测试台
14
解析器组合子:招牌手艺
解析器是值,所以解析器能组合:char 拼成 number,number 拼成 expr,一门小语言半页纸写完。pandoc 就是这么解析半个互联网的。
▸ 组合子工作台
15
并发与 STM:另一种无锁
绿色线程百万起步;atomically 把「读-改-写」变成事务,冲突自动重试,组合两个正确的操作仍然正确——锁做不到的事。
▸ STM 转账台
16
性能与严格性:惰性的账单
惰性不是免费的:foldl 攒出的 thunk 长链会吃光内存、压爆栈。seq、BangPatterns、foldl' 是止血钳;profiling 教你找到出血点。
▸ 空间泄漏观测站
17
工程化:cabal、HLS 与真实项目
建项目、拉依赖、开语言扩展、配 IDE;然后解剖一个真实小项目的目录结构,教你读懂 Hackage 上任何一个包的源码。
STATION V · 回航 RETURN
带着思想顺流而下
学 Haskell 的意义在离开 Haskell 之后:三章把上游思想逐条落回你的日常技术栈。
18
回航 I:带回 Kotlin 与 Java
sealed + when 写 ADT、Arrow 的 Either/Raise、Java 21 的 record + sealed interface + switch 模式匹配、jqwik 属性测试——Android 工程师的逐条落地清单。
19
回航 II:带回 TypeScript 与 Python
判别联合 + never 穷尽检查、neverthrow/Effect、React 里的纯函数思维;Python 侧的 match、dataclass(frozen=True) 与 Hypothesis。
20
生态与下一步:航行图志
教材航线(Haskell MOOC → 本书没讲的深水区)、值得读源码的项目、社区地图;以及一份诚实的清单:什么时候不该用 Haskell。