为长度索引向量实现Applicative实例,构建有限维自由向量空间范畴遇阻
解决索引向量的Applicative实例问题
看起来你在构建带长度索引的向量类型时,卡在了Applicative实例的实现上——毕竟固定长度的向量和普通列表不一样,pure得生成对应长度的元素,<*>得保证两个向量长度匹配才能逐元素应用。我来帮你补全代码并解释关键点:
首先,先把Natural和Vec的GADT定义补完整:
{-# LANGUAGE DataKinds, PolyKinds, MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, GADTs, DeriveTraversable, StandaloneDeriving #-} module Vector where import Control.Category import Control.Applicative -- 类型级自然数 data Natural = Zero | Succ Natural -- 带长度索引的向量GADT data Vec :: Natural -> * -> * where VNil :: Vec 'Zero a VCons :: a -> Vec n a -> Vec ('Succ n) a -- 派生基础类型类实例(方便后续操作) deriving instance Functor (Vec n) deriving instance Foldable (Vec n) deriving instance Traversable (Vec n)
接下来的核心问题是Applicative的pure方法:它需要接收一个值,生成一个任意指定长度n的向量,每个元素都是这个值。这时候我们需要一个辅助类型类来处理不同长度的复制逻辑:
-- 辅助类型类:支持将单个值复制为指定长度的Vec class Replicate n where replicateVec :: a -> Vec n a -- 空向量的复制实例 instance Replicate 'Zero where replicateVec _ = VNil -- 非空向量的复制实例:递归构造更长的向量 instance Replicate n => Replicate ('Succ n) where replicateVec x = VCons x (replicateVec x)
现在就可以基于这个类型类实现Applicative实例了:
-- 给Vec n实现Applicative,约束n必须支持复制逻辑 instance Replicate n => Applicative (Vec n) where -- pure直接复用replicateVec的逻辑生成等长向量 pure = replicateVec -- <*>逐元素应用,GADT的类型保证了两个Vec长度必然匹配,模式匹配不会遗漏 VNil <*> VNil = VNil VCons f fs <*> VCons x xs = VCons (f x) (fs <*> xs)
关键点解释
- GADT的类型保障:
Vec的GADT定义让GHC能在编译期检查向量长度,所以在<*>的实现里,两个Vec n必然是同长度的,完全不需要处理长度不匹配的异常情况。 - Replicate类型类的作用:
pure需要构造任意长度的向量,而不同长度的构造逻辑是递归的,用类型类可以让GHC根据具体的n(Zero或Succ n)自动选择对应的实现。 - 扩展的必要性:你开启的那些编译扩展都是必须的——
DataKinds让我们能把Natural提升到类型层面,GADTs用来定义带索引的Vec,FlexibleInstances允许我们给带约束的Vec n实现Applicative。
如果之后要构建向量空间的Category,态射可以定义为线性映射(比如LinearMap n m a,表示从Vec n a到Vec m a的线性函数),然后给LinearMap实现Category类型类,不过这是后续可以拓展的方向啦。
内容的提问来源于stack exchange,提问作者SingleNegationElimination
相关产品推荐
相关产品推荐

