如何定义仅包装存在特定多参数类型类实例的类型?
解决方案:定义包装存在特定多参数类型类实例的类型
你的核心问题是原代码用了全称量词约束(forall b. SomeClass a b),要求a对所有b都要有SomeClass实例,但你实际需要的是存在量词约束——只要a对至少一个b有SomeClass实例即可。以下是两种实现方式:
方法一:直接打包存在的b约束
修改数据类型,把“存在某个b使得SomeClass a b成立”的约束通过存在量词明确表达,不需要额外辅助类:
{-# LANGUAGE ExistentialQuantification #-} class SomeClass a b where someFunction :: a -> b -> a -- 存在a和b,满足SomeClass a b,就可以包装a的值 data FirstInInstanceOfSomeClass = forall a b. SomeClass a b => First a instance SomeClass Bool String where someFunction = const x = First True -- 现在可以正常编译
这里的forall a b. SomeClass a b => First a表示:只要存在任意一对(a,b)满足SomeClass实例,就允许将a的值包装进来。Bool因为有和String的实例,完全符合条件。
方法二:用辅助类抽象“存在实例”的条件
如果不想在数据类型中隐式携带b的信息,可以定义一个单参数辅助类,专门标记那些存在至少一个SomeClass实例的a:
{-# LANGUAGE ExistentialQuantification, MultiParamTypeClasses, FlexibleInstances #-} class SomeClass a b where someFunction :: a -> b -> a -- 辅助类:标记a存在至少一个SomeClass实例 class HasSomeClassInstance a where witness :: (SomeClass a b) => proxy b -> () -- 只要a对任意b有SomeClass实例,就自动派生这个辅助类的实例 instance SomeClass a b => HasSomeClassInstance a where witness _ = () -- 用辅助类约束筛选可包装的a data FirstInInstanceOfSomeClass = forall a. HasSomeClassInstance a => First a instance SomeClass Bool String where someFunction = const x = First True -- 合法通过编译
这种方式把“存在某个b满足SomeClass a b”的条件,转换成了单参数类HasSomeClassInstance a的约束,让数据类型的定义更简洁。
关键说明
两种方式都满足你的需求:
- 允许
a存在多个以它为第一个参数的SomeClass实例 - 不要求
b函数依赖于a - 只要
a有至少一个符合条件的实例,就能被包装
内容的提问来源于stack exchange,提问作者Seeker
相关产品推荐
相关产品推荐

