ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

fp-ts Bounded 类型类完全指南:为全序类型定义上下界与边界钳制

fp-ts Bounded 类型类完全指南:为全序类型定义上下界与边界钳制 fp-ts Bounded 类型类完全指南为全序类型定义上下界与边界钳制【免费下载链接】fp-tsFunctional programming in TypeScript项目地址: https://gitcode.com/gh_mirrors/fp/fp-tsBounded是 fp-ts 中在Ord全序基础上进一步收窄的一类抽象它不仅定义了类型元素之间的比较关系还规定了该类型在序意义下的最大元素top与最小元素bottom。本文以 docs/modules/Bounded.ts.md 为骨架结合 src/Bounded.ts 的源码实现与 test/Bounded.ts 的测试用例系统讲解Bounded接口、clamp/reverse两个实用工具函数以及它如何支撑Monoid、Semigroup等模块构造出取最小值、最大值的代数结构。读完本文你将掌握如何为自定义类型声明有界序、如何将任意值钳制到合法区间、如何反转一个边界并理解 fp-ts 中Bounded与Ord、number实例之间的真实调用关系。Bounded 是什么在全序之上追加边界Bounded是一个类型类type class它表示具有上界和下界的全序类型。用 src/Bounded.ts 顶部注释中的话说TheBoundedtype class represents totally ordered types that have an upper and lower boundary.也就是说一个类型要成为Bounded首先必须是一个Ord全序任意两个元素都可比较其次必须在序关系中存在唯一的最大元素top和最小元素bottom。典型例子是number任意两个数字可比较大小且Infinity是上界、-Infinity是下界。该类型类自v2.0.0起引入见 src/Bounded.ts 的since 2.0.0标注在 src/index.ts 中作为bounded命名空间整体导出import * as bounded from ./Bounded因此既可以从fp-ts/Bounded按模块引入也可以从fp-ts入口统一使用。Bounded 定律在 Ord 定律之外的追加约束Bounded的实例除了必须满足Ord的全部定律外还必须满足一条额外定律Bounded: bottom a top即对类型A的任意元素a按该实例的比较关系bottom不大于aa不大于top。这条定律保证了bottom与top确实是序意义上的边界而不是任意挑选的两个值。Ord本身的定律包括自反性S.compare(a, a) 0、反对称性与传递性可参见 src/Ord.ts 顶部注释Bounded在其上叠加了边界约束。Bounded 接口Ord 的边界扩展BoundedA接口定义在 src/Bounded.ts 的 model 区域export interface BoundedA extends OrdA { readonly top: A readonly bottom: A }它通过接口继承扩展了 src/Ord.ts 中的OrdAOrd本身又继承EqA包含equals与compare两个字段并额外声明两个只读字段top: A—— 序意义下的最大元素bottom: A—— 序意义下的最小元素。由于Ord已经包含compare: (first, second) Ordering与equals因此构造一个BoundedA实例时你需要同时提供比较逻辑和两个边界值。测试 test/Bounded.ts 展示了最典型的构造方式——基于number的Ord展开并补充边界const B: _.Boundednumber { ...N.Ord, top: 10, bottom: 0 }这里的N.Ord来自 src/number.ts 的Ord实例compare按/返回-1/1/0展开后得到一个0到10之间的有界数字序。现成的 number 实例Bounded仓库为最常用的number类型提供了开箱即用的Bounded实例定义在 src/number.tsexport const Bounded: B.Boundednumber { equals: Eq.equals, compare: Ord.compare, top: Infinity, bottom: -Infinity }该实例以Infinity为上界、-Infinity为下界对应number在全序意义下没有真边界的数学事实——任何有限数字都落在两者之间因此严格满足bottom a top定律。日常开发中建议直接使用import * as N from fp-ts/number后引用N.Bounded。clamp将任意值钳制到 [bottom, top] 区间clamp是Bounded模块中最常用的实用函数自v2.12.0加入export declare const clamp: A(B: BoundedA) (a: A) A签名采用柯里化先传入一个BoundedA实例再传入待处理的元素a返回钳制后的元素。若a小于bottom则返回bottom若a大于top则返回top否则原样返回a。底层实现原理其实现只有一行位于 src/Bounded.tsexport const clamp A(B: BoundedA): ((a: A) A) O.clamp(B)(B.bottom, B.top)它复用了Ord模块的clamp见 src/Ord.tsexport const clamp A(O: OrdA): ((low: A, hi: A) (a: A) A) { const minO min(O) const maxO max(O) return (low, hi) (a) maxO(minO(a, hi), low) }Ord.clamp的实现逻辑是先用min(O)求出a与hi的较小者保证不超上界再用max(O)与low取较大者保证不低于下界即max(min(a, hi), low)。Bounded.clamp的关键在于自动把B.bottom与B.top填入low/hi参数调用者无需再手动传边界。注意这里的min/max分别对应 src/Ord.ts 中的min相等时选第一个参数与max相等时选第一个参数。实测验证test/Bounded.ts 对clamp给出了三组断言const B: _.Boundednumber { ...N.Ord, top: 10, bottom: 0 } const clamp _.clamp(B) clamp(5) // 5落在区间内原样返回 clamp(-1) // 0低于 bottom钳制为 bottom clamp(11) // 10高于 top钳制为 top实战示例分数百分制归一化一个典型的应用场景是数据校验后的区间归一化例如把任意打分钳制到 0100import * as B from fp-ts/Bounded import * as N from fp-ts/number // 自定义一个 0~100 的有界数字序 const scoreBound: B.Boundednumber { ...N.Ord, top: 100, bottom: 0 } const clampScore B.clamp(scoreBound) clampScore(95) // 95 clampScore(-30) // 0 clampScore(150) // 100reverse反转序并交换边界reverse同样自v2.12.0加入作用是反转Bounded实例的比较方向同时交换top与bottomexport declare const reverse: A(B: BoundedA) BoundedA语义上反转一个有界序包含两个动作一是比较关系反转原先是升序反转后为降序二是原本的top在新的序中变成最小元素、原本的bottom变成最大元素因此两者必须互换才能保证反转后依然满足bottom a top定律。底层实现原理源码位于 src/Bounded.tsexport const reverse A(B: BoundedA): BoundedA { const R O.reverse(B) return { equals: R.equals, compare: R.compare, top: B.bottom, bottom: B.top } }实现分两步调用O.reverse(B)得到反转后的Ord。Ord.reverse定义在 src/Ord.ts实现为fromCompare((first, second) O.compare(second, first))即交换两个比较参数等价于compare(a, b)变为compare(b, a)将equals与compare取自反转后的R同时把top赋值为原B.bottom、bottom赋值为原B.top。实测验证test/Bounded.ts 验证了边界交换行为const B: _.Boundednumber _.reverse({ ...N.Ord, top: 10, bottom: 0 }) B.top // 0原 bottom B.bottom // 10原 top实战示例排行榜降序有界区间例如要处理最高分优先级最高的降序场景同时仍希望保留边界语义分数不超出 0100import * as B from fp-ts/Bounded const asc: B.Boundednumber { ...N.Ord, top: 100, bottom: 0 } const desc B.reverse(asc) desc.compare(90, 10) // -190 在降序中更小更靠前 desc.top // 0 desc.bottom // 100从源码看 Bounded 的生态位置Bounded在 fp-ts 中并不是孤立模块它向下依赖Ord向上支撑多个代数结构的构造器支撑 Monoid 的 min / max 构造器src/Monoid.ts 使用Bounded构造取最小值和最大值的Monoidexport const min A(B: BoundedA): MonoidA ({ concat: Se.min(B).concat, empty: B.top }) export const max A(B: BoundedA): MonoidA ({ concat: Se.max(B).concat, empty: B.bottom })逻辑非常直观取最小值的幺半群其恒等元必须是不影响取最小值结果的值即序的最大元素top反之取最大值的幺半群恒等元为bottom。而concat复用 src/Semigroup.ts 中基于Ord的min/max内部调用Or.min(O)/Or.max(O)即 src/Ord.ts 的min/max。这形成一个清晰的依赖链Bounded→Ord→ 比较原语。典型用法import * as N from fp-ts/number import * as M from fp-ts/Monoid const minMonoid M.min(N.Bounded) minMonoid.concat(1, 2) // 1 minMonoid.empty // Infinity const maxMonoid M.max(N.Bounded) maxMonoid.concat(1, 2) // 2 maxMonoid.empty // -Infinity为 Const 提供有界实例src/Const.ts 通过getBounded将任意BoundedE提升为BoundedConstE, Aexport const getBounded: E, A(B: BoundedE) BoundedConstE, A identity as any它利用Const类型擦除的特性直接复用底层BoundedE说明Bounded作为携带序信息的实例可以借助类型构造器在更复杂的结构中传播。依赖关系小结BoundedA继承OrdAsrc/Bounded.tsOrdA继承EqAsrc/Ord.tsnumber模块提供现成的Boundednumber实例src/number.tsMonoid.min/Monoid.max消费Bounded实例src/Monoid.tsConst.getBounded复用Bounded实例src/Const.ts。迁移说明boundedNumber 已废弃原Bounded模块在 v2.0.0 曾导出一个名为boundedNumber的Boundednumber常量现已被标记为deprecatedzone of death不再建议直接使用export declare const boundedNumber: Boundednumber其历史实现见 src/Bounded.ts 的 deprecated 区域为export const boundedNumber: Boundednumber { equals: O.ordNumber.equals, compare: O.ordNumber.compare, top: Infinity, bottom: -Infinity }它的功能与现在的N.Bounded完全等价。官方迁移指引是改用number模块中的Bounded实例即import * as N from fp-ts/number后使用N.Bounded。这一迁移也符合 fp-ts v2.10 将各基础类型的实例收敛到对应模块number、string、boolean等的整体设计趋势。如果你的代码中仍在使用boundedNumber编译时会出现废弃警告建议按此路径平滑升级。小结Bounded在 fp-ts 的类型类体系中扮演有边界的全序这一角色BoundedA extends OrdA并追加top/bottom两个边界字段实例必须满足bottom a top定律。围绕它clamp把任意值钳制到边界区间复用Ord.clamp并以B.bottom/B.top自动填充reverse在反转比较方向的同时交换上下界复用Ord.reverse。在生态上它是Monoid.min/Monoid.max构造器的输入来源也被Const.getBounded复用。对于数字等常见类型直接使用N.Boundedtop: Infinity、bottom: -Infinity即可不必再碰已废弃的boundedNumber。相关实现与验证可进一步阅读 src/Bounded.ts、src/Ord.ts、src/number.ts、src/Monoid.ts 与 test/Bounded.ts。【免费下载链接】fp-tsFunctional programming in TypeScript项目地址: https://gitcode.com/gh_mirrors/fp/fp-ts创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表