Chapter 8. Working effectively with multi-argument functions
覆盖elevated function application、functor/applicative/monad、monad laws、LINQ composition与Bind/Apply选择,处理多个contextual inputs。
学习目标
- 能推导Map、Apply、Bind、Traverse在plain/elevated function与values之间的type shape
- 能解释functor、applicative与monad laws的refactoring意义,设计property tests验证custom context
- 能判断independent/dependent/mixed effects选择Apply、Bind、LINQ或explicit staging
机制总览
Chapter 8. Working effectively with multi-argument functions:机制路径
- 1
为什么Multi-Argument Function遇到C…
普通 Func 接plain A/B;现实中inputs常是Option A、Validation B、Task A。先unwrap再if会重复control flow。Applicative Apply把elevated function用于elevated values,Bind处理later …
- 2
Function application in the e…
Map处理一个elevated value;Apply处理elevated function和elevated argument,多次Apply可组合multi-arg function。Independent field validations可全部运行并积累error。Bind适合functio…
- 3
Functors, applicatives, monads
Functor提供Map;applicative增加pure/lift与Apply;monad增加Bind。它们是能力层级和laws,不是class inheritance要求。一个context可以有Map/Apply/Bind,但若实现不满足laws,重构/组合会改变semantics。
章级决策实验
Chapter 8. Working effectively with multi-argument functions:机制与证据
切换《Chapter 8. Working effectively with multi-argument functions》的三个关键教学阶段,先解释机制,再用运行与失败证据验证结论。
选择推理阶段
当前阶段 · 为什么Multi-Argument Function遇到C…
普通 Func 接plain A/B;现实中inputs常是Option A、Validation B、Task A。先unwrap再if会重复control flow。Applicative Apply把elevated function用于elevated values,Bind处理later …
可核验证据
以确定输入重复运行「为什么Multi-Argument Function遇到C…」的最小管线,用属性测试、状态快照和副作用调用轨迹核对返回值、失败传播与资源边界。
学完《Chapter 8. Working effectively with multi-argument functions》后,应能从输入和前置条件推导状态变化,并用可重复的构建、运行或边界测试证明结果。
失效—证据矩阵
Chapter 8. Working effectively with multi-argument functions:失效与核验
为什么Multi-Argument Function遇到C…
典型失效
若把「为什么Multi-Argument Function遇到C…」只写成函数式术语而不隔离副作用、状态和失败分支,组合后的程序仍会依赖隐藏时序,无法从输入稳定推导结果。
核验证据
以确定输入重复运行「为什么Multi-Argument Function遇到C…」的最小管线,用属性测试、状态快照和副作用调用轨迹核对返回值、失败传播与资源边界。
Function application in the e…
典型失效
若把「Function application in the e…」只写成函数式术语而不隔离副作用、状态和失败分支,组合后的程序仍会依赖隐藏时序,无法从输入稳定推导结果。
核验证据
以确定输入重复运行「Function application in the e…」的最小管线,用属性测试、状态快照和副作用调用轨迹核对返回值、失败传播与资源边界。
Functors, applicatives, monads
典型失效
若把「Functors, applicatives, monads」只写成函数式术语而不隔离副作用、状态和失败分支,组合后的程序仍会依赖隐藏时序,无法从输入稳定推导结果。
核验证据
以确定输入重复运行「Functors, applicatives, monads」的最小管线,用属性测试、状态快照和副作用调用轨迹核对返回值、失败传播与资源边界。
为什么Multi-Argument Function遇到Context就需要新工具
普通Func<A,B,R>接plain A/B;现实中inputs常是Option A、Validation B、Task A。先unwrap再if会重复control flow。Applicative Apply把elevated function用于elevated values,Bind处理later input依赖earlier value,Traverse翻转list/context。工具选择来自dependency graph。
先预测:两个Options组合一定用Bind吗;Apply是否可以让dependent validation工作;能写SelectMany是否证明monad laws;LINQ query syntax是否只用于IEnumerable;Task+Either是否能直接flatten为一种effect。答案都是否。
↡Value或function位于Option、Either、Task等context内,而非plain type层的状态。Function application in the elevated world
Map处理一个elevated value;Apply处理elevated function和elevated argument,多次Apply可组合multi-arg function。Independent field validations可全部运行并积累error。Bind适合function本身返回context且依赖前值;Traverse把多个contextual computations聚合成一个contextual list。
Validation<Func<Name, Email, Customer>> create = Valid(Customer.Create);
Validation<Customer> customer = create
.Apply(ValidateName(dto.Name))
.Apply(ValidateEmail(dto.Email));切换Map、Apply、Bind与Traverse
Functors, applicatives, monads
Functor提供Map;applicative增加pure/lift与Apply;monad增加Bind。它们是能力层级和laws,不是class inheritance要求。一个context可以有Map/Apply/Bind,但若实现不满足laws,重构/组合会改变semantics。
名字帮助跨Option/Either/Task/IEnumerable识别pattern,domain code仍应使用业务词。不要在每个call site讲category theory;library implementer和reviewer必须理解laws,workflow reader看清data/failure flow即可。
↡Context提供Map/Apply/Bind等组合能力并满足对应identity/composition/associativity laws的语义约定。The monad laws
Left identity:把value放入context再Bind f,等价f(value);right identity:m Bind pure等价m;associativity:(m Bind f) Bind g等价m Bind (x => f(x) Bind g)。Equality按context observable semantics,例如sequence order/error choice/effect count。
Prop.ForAll<Value>(value =>
Pure(value).Bind(Parse).Equals(Parse(value)));切换functor、applicative、monad与effect equality
Equality and effect evidence
Law test先定义“相等”再生成样本:Option比较Some/None和值,Either还比较chosen error,IEnumerable比较元素与顺序,Task则需同时观察completion、fault、cancellation及effect trace。对会访问时钟、网络或日志的function,用recording interpreter收集调用次数、参数与顺序,不能只比较最终value,否则重复执行effect的错误仍会伪装成law成立。Generator还应覆盖empty、boundary、Left/Right与throwing function,并在失败时保留可复现seed和最小反例。
Improving readability by using LINQ with any monad
C# query syntax通过Select/SelectMany/Where pattern可用于自定义Option/Either等context。From clauses为intermediate values命名,适合dependent chain;最终compiler仍调用methods,不自动处理mixed contexts或验证laws。
var result =
from customer in FindCustomer(id)
from order in FindLatestOrder(customer.Id)
select BuildSummary(customer, order);LINQ提高readability的前提是一个consistent context和abstraction level。若每行转换Task/Either/Option层,explicit named helpers可能更清楚。
↡C# query syntax把Select/SelectMany chains投影为可命名intermediate values的monadic composition。When to use Bind vs. Apply
Independent computations用Apply,可parallel或accumulate;dependent computations用Bind,后一步需要前值且前失败就跳过。选择是data dependency,不是个人style。Task+Validation等mixed effects需Traverse/helper或分阶段;不要用嵌套Bind制造金字塔。
切换independent、dependent、LINQ与mixed effects
本章回顾:Context里的多参数组合由Dependency决定
- Map、Apply、Bind、Traverse对应不同plain/elevated shapes。
- Functor/applicative/monad是能力+laws,不是标签。
- Laws保护regrouping与refactor的observable equivalence。
- LINQ可表达monadic dependent chains,但不解决mixed effects。
- Independent用Apply,dependent用Bind,复杂layers显式staging。
练习
问题 1:Name和Email validation为什么适合Apply?
问题 2:Custom Option应测试哪些laws?
问题 3:Task of Either list如何组合?
术语表
名词解释
本章出现的专业名词,用大白话再讲一遍。
- elevated value
- applicative apply
- context composition contract
- LINQ monadic notation
- dependency-shaped composition
原版目录概念补充核对
以下条目补齐官方目录中容易被示例主线掩盖的概念。它们不重复罗列目录,而是明确每项概念的机制、适用边界和验收证据。
Functors, applicatives, monads:机制、边界与证据
Chapter 8. Working effectively with multi-argument functions中的Functors, applicatives, monads应写成可组合的输入—输出契约,并把环境读取、状态改变与失败显式放在边界。用确定输入运行正常、空值和失败样本,同时记录返回值与副作用轨迹,证明结论不依赖隐藏状态。
The monad laws:机制、边界与证据
Chapter 8. Working effectively with multi-argument functions中的The monad laws应写成可组合的输入—输出契约,并把环境读取、状态改变与失败显式放在边界。用确定输入运行正常、空值和失败样本,同时记录返回值与副作用轨迹,证明结论不依赖隐藏状态。
When to use Bind vs. Apply:机制、边界与证据
Chapter 8. Working effectively with multi-argument functions中的When to use Bind vs. Apply应写成可组合的输入—输出契约,并把环境读取、状态改变与失败显式放在边界。用确定输入运行正常、空值和失败样本,同时记录返回值与副作用轨迹,证明结论不依赖隐藏状态。