如何为含特定类型的Coproduct实现MyFun类实例?
问题描述
假设存在构造器种类为Coproduct :: [*] -> *的Coproduct数据类型,以及如下带函数依赖的MyFun类:
class MyFun s x | x -> s where myFun :: s -> x
需求是:当类型列表xs包含某类型x时,自动生成instance MyFun s x => MyFun s (Coproduct xs)形式的实例。
已编写的类型族
为实现需求,先编写了以下类型族:
type family SplitAt (x :: a) (xs :: [a]) :: ([a], [a]) where SplitAt x '[] = '( '[] , '[] ) SplitAt x (x ': q) = '( '[], q) SplitAt x (y ': q) = '( y ': Fst (SplitAt x q), Snd (SplitAt y q)) type family ConcatWith (x :: a) (s :: ([a], [a])) :: [a] where ConcatWith x '( '[], xs) = x ': xs ConcatWith x '(y ': q, xs) = y ': ConcatWith x '(q, xs) type family Fst (p :: (a, b)) :: a where Fst '(a, b) = a type family Snd (p :: (a, b)) :: b where Snd '(a, b) = b
尝试方案1
编写了如下实例声明:
instance (MyFun s x, b ~ ConcatWith x (SplitAt x xs)) => MyFun s (Coproduct b) where myFun = -- 后续无关代码
但触发错误:
Illegal instance declaration for ‘MyFun s (Coproduct b)’ The liberal coverage condition fails in class ‘MyFun’ for functional dependency: ‘m -> s’ Reason: lhs type ‘Coproduct b’ does not determine rhs type ‘s’ Un-determined variable: s • In the instance declaration for ‘MyFun s (Coproduct b)’
错误原因明确:GHC无法识别列表b中必然包含x,因此无法继承x对应的实例的函数依赖。
尝试方案2
改用TypeFamilies扩展实现,调整后的类和实例如下:
class MyFun x where type ArgMyFun x myFun :: ArgMyFun x -> x instance (MyFun x, b ~ ConcatWith x (SplitAt x xs)) => MyFun (Coproduct b) where type ArgMyFun (Coproduct (ConcatWith b)) = ArgMyFun x myFun = -- ...
同样失败,错误信息:
error: The RHS of an associated type declaration mentions out-of-scope variable ‘x’ All such variables must be bound on the LHS
错误原因:关联类型声明的右侧引用了未在左侧绑定的变量x。
临时解决办法
目前找到的唯一(粗糙) workaround 是:
instance (MyFun s x) => MyFun s (Either x (Coproduct xs)) where myFun x = --...
该方案将x显式放入类型中,仅使用Either的Right部分,但明显不符合预期。
内容的提问来源于stack exchange,提问作者141592653
相关产品推荐
相关产品推荐

