Generics: ADT времени выполнения для типов с экземплярами - PullRequest
0 голосов
/ 28 мая 2020

Возможно ли с помощью Haskell / GH C извлечь тип данных algebrai c, представляющий все типы с экземплярами Eq и Ord? Вероятно, для этого потребуются Generics, Typeable, et c.

Я бы хотел что-то вроде:

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

Для всех типов, которые, как известно, имеют экземпляры для Eq и Ord. Если это упростит решение, мы можем ограничить нашу область действия экземплярами Ord, поскольку Eq подразумевается Ord. Но было бы интересно узнать, возможно ли пересечение ограничений.

Этот тип данных был бы полезен, потому что он дает возможность использовать его там, где требуются ограничения Eq и Ord, и сопоставление с образцом во время выполнения для уточнения types.

Мне это понадобится для реализации общего c Map Key Value, где Key будет этим типом, в библиотеке индексирования документов, где ключи и их тип известны во время выполнения. Эта библиотека здесь . На данный момент я обошел проблему, определив классы data DocIndexKey и FieldKey, но это не совсем удовлетворительно, поскольку для этого требуется шаблонный код и не могут быть охвачены все кандидаты в файлы git.

Приветствуется любой хороший альтернативный подход к этой ситуации. По некоторым причинам я предпочитаю избегать шаблона Haskell.

1 Ответ

1 голос
/ 29 мая 2020

Ну, это не 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

Исчерпание намного сложнее. Возможно, с помощью плагина вы могли бы заставить GH C сделать это, но зачем? Я не верю, что GH C на самом деле пытается отслеживать, какие типы он видел. В частности, вам придется сканировать все модули в проекте и его зависимости, даже те, которые не были загружены модулем, содержащим определение типа. Придется реализовать его с нуля. И, как показывает этот ответ, я очень сомневаюсь, что вы действительно сможете использовать такую ​​исчерпывающую способность для всего, что вы еще не можете сделать, просто принимая открытую вселенную такой, какая она есть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...