如何在fp-ts中实现数组排序?Ord与contramap相关技术疑问
1. Ord的作用是什么?
Ord是fp-ts中的类型类,核心是为类型定义可复用的排序规则。它基于Eq(相等判断类型类)扩展,提供了compare函数——该函数接收同类型的两个值,返回-1、0、1分别代表前者小于、等于、大于后者。
简单来说,Ord就是给某个类型“赋予排序能力”的契约。比如string类型的Ord实例,定义了字符串按字典序比较的逻辑;number的Ord实例则对应数值大小比较逻辑。没有Ord,sortBy就无法判断数组元素的先后顺序。
2. contramap的作用是什么?
contramap是Ord类型类的方法,作用是将已有类型的Ord规则,转换为关联类型的Ord规则。
举个实际例子:如果你有一个用户对象{ name: string },想按name排序,但手里只有字符串的Ord实例。这时就可以用contramap,把字符串的排序规则“映射”到用户对象上——告诉Ord:要比较两个用户,先提取他们的name字段,再用字符串的规则比较。
代码示例:
import { ordString } from 'fp-ts/Ord' import { contramap } from 'fp-ts/Ord' type User = { name: string } const ordUserByName = contramap((user: User) => user.name)(ordString)
这里contramap先接收一个“字段提取函数”(从User中取出name),再传入原Ord实例(ordString),最终返回一个适用于User类型的新Ord实例。
3. 如何构建该排序函数?
结合sortBy、Ord和contramap,可针对不同场景构建排序函数:
场景1:排序基础类型数组(如字符串数组)
直接使用sortBy配合对应类型的Ord实例即可:
import { sortBy } from 'fp-ts/Array' import { ordString } from 'fp-ts/Ord' // 生成字符串数组排序函数 const sortStrings = sortBy([ordString]) // 使用示例 const sorted = sortStrings(['banana', 'apple', 'cherry']) // 输出:['apple', 'banana', 'cherry']
sortBy接受一个Ord实例数组(支持多字段排序:先按第一个Ord规则排序,再按第二个规则处理同优先级元素),返回对应的数组排序函数。
场景2:排序自定义对象数组
比如排序用户数组,按name字典序排列:
import { sortBy } from 'fp-ts/Array' import { ordString, contramap } from 'fp-ts/Ord' type User = { name: string; age: number } // 构建按name排序的Ord实例 const ordUserByName = contramap((user: User) => user.name)(ordString) // 生成用户数组排序函数 const sortUsersByName = sortBy([ordUserByName]) // 使用示例 const users = [ { name: 'Bob', age: 30 }, { name: 'Alice', age: 25 }, { name: 'Charlie', age: 35 } ] const sortedUsers = sortUsersByName(users) // 输出:[{ name: 'Alice', ... }, { name: 'Bob', ... }, { name: 'Charlie', ... }]
如果需要多字段排序(比如先按age升序,再按name升序),只需传入多个Ord实例:
import { ordNumber } from 'fp-ts/Ord' const ordUserByAge = contramap((user: User) => user.age)(ordNumber) const sortUsersByAgeThenName = sortBy([ordUserByAge, ordUserByName])
内容的提问来源于stack exchange,提问作者Woww

