
关于
实用、无术语的函数式编程指南 — 80/20 方法,无需学术开销即可获得成果。
name: fp-pragmatic description: 实用的、无术语的函数式编程指南——用 80/20 法则获得成果,无需学术开销 risk: unknown source: community version: 1.0.0 author: kadu tags:
- fp-ts
- functional-programming
- typescript
- pragmatic
- beginner-friendly
- best-practices
实用函数式编程
先读这个。 本指南穿透学术术语,展示真正重要的内容。没有范畴论。没有抽象废话。只有让你的代码更好的模式。
何时使用
- 你想要一个 fp-ts 或 TypeScript 函数式编程的实用起点。
- 任务是探索性或教育性的,需要一个 80/20 视角来了解什么真正值得采用。
- 你需要关于 FP 何时有帮助、何时保持代码简单更好的指导。
黄金法则
如果函数式编程让你的代码更难读,就不要用它。
FP 是工具,不是信仰。有帮助时用它。没帮助时跳过。
FP 的 80/20
这五个模式给你大部分好处。在探索其他任何东西之前先掌握这些。
1. Pipe:清晰地链接操作
不要嵌套函数调用或创建中间变量,按阅读顺序链接操作。
import { pipe } from 'fp-ts/function'
// Before: Hard to read (inside-out)
const result = format(validate(parse(input)))
// Before: Too many variables
const parsed = parse(input)
const validated = validate(parsed)
const result = format(validated)
// After: Clear, linear flow
const result = pipe(
input,
parse,
validate,
format
)
何时使用 pipe:
- 对同一数据进行 3 次以上转换
- 你发现自己在命名一次性变量
- 逻辑从上到下读起来更好
何时跳过 pipe:
- 只有 1-2 个操作(直接调用就好)
- 操作不能自然链接
2. Option:无需 null 检查处理缺失值
停止到处写 if (x !== null && x !== undefined)。
import * as O from 'fp-ts/Option'
import { pipe } from 'fp-ts/function'
// Before: Defensive null checking
function getUserCity(user: User | null): string {
if (user === null) return 'Unknown'
if (user.address === null) return 'Unknown'
if (user.address.city === null) return 'Unknown'
return user.address.city
}
// After: Chain through potential missing values
const getUserCity = (user: User | null): string =>
pipe(
O.fromNullable(user),
O.flatMap(u => O.fromNullable(u.address)),
O.flatMap(a => O.fromNullable(a.city)),
O.getOrElse(() => 'Unknown')
)
通俗翻译:
O.fromNullable(x)= "包装这个值,将 null/undefined 视为'无'"O.flatMap(fn)= "如果我们有值,应用这个函数"O.getOrElse(() => default)= "解包,如果为空则使用这个默认值"
3. Either:让错误显式化
停止为预期的失败抛出异常。将错误作为值返回。
import * as E from 'fp-ts/Either'
import { pipe } from 'fp-ts/function'
// Before: Hidden failure mode
function parseAge(input: string): number {
const age = parseInt(input, 10)
if (isNaN(age)) throw new Error('Invalid age')
if (age < 0) throw new Error('Age cannot be negative')
return age
}
// After: Errors are visible in the type
function parseAge(input: string): E.Either<string, number> {
const age = parseInt(input, 10)
if (isNaN(age)) return E.left('Invalid age')
if (age < 0) return E.left('Age cannot be negative')
return E.right(age)
}
// Using it
const result = parseAge(userInput)
if (E.isRight(result)) {
console.log(`Age is ${result.right}`)
} else {
console.log(`Error: ${result.left}`)
}
通俗翻译:
E.right(value)= "成功,带有这个值"E.left(error)= "失败,带有这个错误"E.isRight(x)= "成功了吗?"
4. Map:无需解包即可转换
在容器内转换值,无需先提取它们。
import * as O from 'fp-ts/Option'
import * as E from 'fp-ts/Either'
import * as A from 'fp-ts/Array'
import { pipe } from 'fp-ts/function'
// Transform inside Option
const maybeUser: O.Option<User> = O.some({ name: 'Alice', age: 30 })
const maybeName: O.Option<string> = pipe(
maybeUser,
O.map(user => user.name)
)
// Transform inside Either
const result: E.Either<Error, number> = E.right(5)
const doubled: E.Either<Error, number> = pipe(
result,
E.map(n => n * 2)
)
// Transform arrays (same concept!)
const numbers = [1, 2, 3]
const doubled = pipe(
numbers,
A.map(n => n * 2)
)
5. FlatMap:链接可能失败的操作
当每一步都可能失败时,将它们链接在一起。
import * as E from 'fp-ts/Either'
import { pipe } from 'fp-ts/function'
const parseJSON = (s: string): E.Either<string, unknown> =>
E.tryCatch(() => JSON.parse(s), () => 'Invalid JSON')
const extractEmail = (data: unknown): E.Either<string, string> => {
if (typeof data === 'object' && data !== null && 'email' in data) {
return E.right((data as any).email)
}
return E.left('No email field')
}
// Chain them
const getEmailFromJSON = (input: string) =>
pipe(
input,
parseJSON,
E.flatMap(extractEmail)
)
兼容工具
Claude CodeCursor
标签
AI与机器学习