假设我们正在编写一个简单的bitset,它使用c
类型的字段(想象Word
)来表示类型a
的不同值的存在:
data BitSet c a = BitSet c
deriving (Eq, Ord, Data, Typeable, Generic, NFData)
isSet :: (Bits c, Enum a) => a -> BitSet c a -> Bool
isSet e (BitSet c) = testBit c $ fromEnum e
假设{p> a
为Enum
,因此可以将其转换为与位索引对应的整数。
现在让我们尝试为Foldable
编写BitSet c
个实例,从以下开始:
instance FiniteBits c => Foldable (BitSet c) where
foldr f b0 (BitSet c) = foldr f b0 list
where (list :: [a]) = toEnum <$> filter (testBit c) [0..finiteBitSize c - 1]
但是这不起作用:它没有a
应该满足Enum a
的约束,我没有看到任何提供它的方法(我有一种直觉感觉到如果a
未在实例声明中列出,那么从更理论的角度来看,它没有多大意义,但这可能是另一个故事。)
投票最多的答案here表明使用GADT可能有所帮助,但GADT有其自身的缺点:
还有其他方法可以在保留自动获取的通用实例的同时编写Foldable
实例吗?