Haskell自定义Category报错:No instance for (Id (HFun a a))
问题分析与解决
你的代码编译失败的核心原因是:额外定义的Id类无法让编译器推导出任意类型列表l对应的Id (HFun l l)实例。你在Category HFun实例中调用id时,编译器无法确认这个实例存在,因此报错。
解决方案:去掉冗余的Id类,用类型类辅助实现范畴的id
首先修正数据构造器的语法(你代码里的:->:是HTML转义后的符号,Haskell中应使用(:->)),然后通过专门的类型类来递归生成HFun的恒等态射,最后实现Category实例:
{-# LANGUAGE GADTs, TypeOperators, FlexibleInstances #-} type Cat i = i -> i -> Type class Category (h :: Cat i) where id :: h a a (.) :: h b c -> h a b -> h a c -- 修正后的HFun定义 data HFun (l :: [Type]) (l' :: [Type]) where HFunNil :: HFun '[] '[] (:->) :: (a -> b) -> HFun as bs -> HFun (a ': as) (b ': bs) -- 辅助类型类:为任意类型列表生成HFun的恒等态射 class HFunId (xs :: [Type]) where hFunId :: HFun xs xs instance HFunId '[] where hFunId = HFunNil instance HFunId xs => HFunId (x ': xs) where hFunId = Prelude.id :-> hFunId -- 实现Category实例 instance Category HFun where id = hFunId -- 补充实现(.)运算符(范畴必须满足结合律) (.) HFunNil HFunNil = HFunNil (.) (f :-> fs) (g :-> gs) = (f . g) :-> (fs . gs)
关键说明
- 去掉冗余的
Id类:你原本的Id类和Prelude中的id重名,容易造成混淆,且完全可以用更针对性的HFunId替代。 HFunId类型类通过递归实例,为任意长度的类型列表生成对应的恒等HFun:空列表对应HFunNil,非空列表则拼接Prelude.id和子列表的恒等态射。- 补充
(.)的实现:范畴必须实现复合运算符,且满足结合律,这里的实现递归地复合每个位置的函数。
内容的提问来源于stack exchange,提问作者soufiane maguerra
相关产品推荐
相关产品推荐

