泛型:带有实例的类型的运行时ADT

时间:2020-05-28 09:36:00

标签: haskell

Haskell / GHC是否可以提取表示所有带有Eq和Ord实例的类型的代数数据类型?这可能需要泛型,可类型化等。

我想要的是这样的:

data Data_Eq_Ord = Data_String String 
                 | Data_Int Int
                 | Data_Bool Bool
                 | ...
deriving (Eq, Ord)

对于所有已知具有Eq和Ord实例的类型。如果它使解决方案更容易,则可以将范围限制为Ord实例,因为Ed隐含了Eq。但是知道约束交叉是否可能会很有趣。

此数据类型很有用,因为它使得可以在需要Eq和Ord约束的地方使用它,并在运行时进行模式匹配以优化类型。

我将需要它在文档索引库中实现一个通用的Map Key Value,其中Key将是这种类型,在运行时已知其键及其类型。该库为here。目前,我通过定义data DocIndexKeyFieldKey类来解决该问题,但这并不完全令人满意,因为它需要样板,并且不能涵盖所有合法候选人。

欢迎任何一种替代这种情况的好方法。由于某些原因,我宁愿避免使用Template Haskell。

1 个答案:

答案 0 :(得分:1)

好吧,它不是ADT,但这绝对有效:

data Satisfying c = forall a. c a => Satisfy a
class (l a, r a) => And l r a where
instance (l a, r a) => And l r a where

ex :: [Satisfying (Typeable `And` Show `And` Ord)]
ex = [ Satisfy (7 :: Int)
     , Satisfy "Hello"
     , Satisfy (5 :: Int)
     , Satisfy [10..20 :: Int]
     , Satisfy ['a'..'z']
     , Satisfy ((), 'a')]

-- An example of use, with "complicated" logic
data With f c = forall a. c a => With (f a)
--                 vvvvvvvvvvvvvvvvvvvvvvvvvv QuantifiedConstraints chokes on this, which is probably a bug...
partitionTypes :: (forall a. c a => TypeRep a) -> [Satisfying c] -> [[] `With` c]
partitionTypes rep = foldr go []
   where go (Satisfy x) [] = [With [x]]
         go x'@(Satisfy (x :: a)) (xs'@(With (xs :: [b])) : xss) =
             case testEquality rep rep :: Maybe (a :~: b) of
                 Just Refl -> With (x : xs) : xss
                 Nothing -> xs' : go x' xss

main :: IO ()
main = traverse_ (\(With xs) -> print (sort xs)) $ partitionTypes typeRep ex

穷举要困难得多。也许有了插件,您可以让GHC来做,但是为什么要麻烦呢?我不相信GHC实际上试图跟踪所见类型。特别是,您必须扫描项目中的所有模块及其依赖项,即使那些尚未由包含类型定义的模块加载的模块也是如此。您必须从头开始实施它。而且,正如这个答案所显示的,我非常怀疑您是否真的可以通过仅使用开放宇宙来使用这种您不可能做的事情。

相关问题