如何在Haskell中指定具有多参数单射性的类型族?
解决方法
方法1:多参数类型类 + 函数依赖
如果可以重构AA类的结构,最直接的方式是把Context a、B a、C a作为显式参数加入类型类,同时用函数依赖声明这三个参数能唯一确定a:
{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE TypeFamilies #-} class A a where type Context a -- 函数依赖 ctx b c -> a 表示:给定ctx、b、c,a是唯一的 class (A a, Context a ~ ctx) => AA ctx b c a | ctx b c -> a where type B a = b type C a = c problematic :: ctx -> b -> c -> a
这里Context a ~ ctx用来保证类中显式的ctx参数和A类里的关联类型Context a一致,函数依赖则强制了三个输入类型到a的唯一性约束。
方法2:TypeFamilyDependencies 扩展(GHC 8.0+)
要是想保留AA a这种单参数类的结构,可以用GHC的TypeFamilyDependencies扩展,把三个关联类型打包成一个元组类型家族,再声明这个元组到a的单射依赖:
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilyDependencies #-} class A a where type Context a class A a => AA a where type B a type C a -- 打包三个关联类型,并声明:给定这个元组,a是唯一的 type ABC a = (Context a, B a, C a) | (Context a, B a, C a) -> a problematic :: Context a -> B a -> C a -> a
这个方式不需要改动原有类的参数结构,通过新增的ABC类型家族间接实现了“Context、B、C组合唯一确定a”的约束。
约束的有效性
不管用哪种方法,只要你尝试定义两个不同的a实例,且它们的Context、B、C完全相同,GHC就会检测到依赖冲突,直接报错拒绝编译,保证了约束的有效性。
内容的提问来源于stack exchange,提问作者Gusten
相关产品推荐
相关产品推荐

