如何自动生成PureScript枚举全值数组并确保其完整性?
PureScript枚举类型全值数组的生成与校验方案
先看你定义的代码:
data Icon = IconCircle | IconSquare | IconStar
还有对应的全值数组:
allPossible :: Array Icon allPossible = [IconCircle, IconSquare, IconStar]
一、快捷生成全值数组的办法
PureScript本身没有自动生成枚举全值的原生语法,但可以用类型类来简化维护:
- 先定义一个
Enumerable类型类,专门用来获取某个类型的所有取值:
class Enumerable a where allValues :: Array a
- 给
Icon实现这个类型类:
instance enumerableIcon :: Enumerable Icon where allValues = [IconCircle, IconSquare, IconStar]
第一次还是要手动列全,但后续如果新增Icon的取值,只需要修改这个实例里的数组就行,不用到处找引用,逻辑更集中。
另外社区里有purescript-enums这类库,提供了现成的枚举处理工具,能进一步简化全值生成的代码。
二、用类型系统强制数组不遗漏取值
如果想从类型层面确保数组包含所有Icon取值,可以借助PureScript的类型级编程能力:
方案:类型级长度校验
核心思路是让编译器检查数组的长度和Icon构造器的数量完全一致——只要新增构造器但没更新数组,编译直接报错。
- 先把
Icon的构造器映射到类型行,再定义计算类型行长度的类型家族:
-- 用类型行列出所有Icon构造器 type IconConstructors = (circle :: Unit, square :: Unit, star :: Unit) -- 类型级函数:计算类型行的长度 type family RowLength (r :: # Type) :: Nat type instance RowLength () = 0 type instance RowLength (l :: a | r) = 1 + RowLength r -- 定义带长度约束的数组类型 type ExactLengthArray (n :: Nat) a = { length :: n, content :: Array a } -- 辅助函数:编译期检查数组长度是否匹配 mkExactLengthArray :: forall n a. SNat n -> Array a -> Maybe (ExactLengthArray n a) mkExactLengthArray n arr = if length arr == reflectNat n then Just { length: n, content: arr } else Nothing
- 用这个约束定义
allPossible:
allPossible :: ExactLengthArray (RowLength IconConstructors) Icon allPossible = case mkExactLengthArray (snat :: SNat (RowLength IconConstructors)) [IconCircle, IconSquare, IconStar] of Just arr -> arr.content Nothing -> error "allPossible数组长度和Icon构造器数量不匹配"
这样以后只要给Icon加新的构造器,比如IconTriangle,就得同步更新IconConstructors类型行和allPossible数组,否则编译通不过,从根源避免遗漏。
总结
- 快捷维护:用
Enumerable类型类把全值数组集中管理,或者用社区枚举库减少重复代码。 - 类型安全:通过类型级长度校验,让编译器帮你把关数组是否包含所有枚举取值,不用手动检查。
内容的提问来源于stack exchange,提问作者christian wuensche
相关产品推荐
相关产品推荐

