название этого, по общему признанию, не очень описательное, но я не знаю, как еще описать это в коротком названии. Буду признателен за любые рекомендации!
Я собираюсь представить очень упрощенную версию моей проблемы :)
Итак, у меня есть класс типов
class Known f a where
known :: f a
Предполагается, что он может генерировать каноническую конструкцию данного типа по определенному индексу, что полезно для работы с GADT и прочим. Я даю упрощенную версию этого, с соответствующими частями.
Так что, очевидно, есть экземпляр для Proxy
:
instance Known Proxy a where
known = Proxy
Что мы можем использовать:
> known :: Proxy Monad
Proxy
Но есть также экземпляр для типа, подобного HList:
data Prod f :: [k] -> * where
PNil :: Prod f '[]
(:<) :: f a -> Prod f as -> Prod f (a ': as)
infixr 5 (:<)
Где Prod f '[a,b,c]
будет примерно эквивалентно кортежу (f a, f b, f c)
. Тот же функтор, разные типы.
Написать экземпляр достаточно просто:
instance Known (Prod f) '[] where
known = PNil
instance (Known f a, Known (Prod f) as) => Known (Prod f) (a ': as) where
known = known :< known
Что работает довольно хорошо: (при условии, что экземпляр Show)
> known :: Prod Proxy '[1,2,3]
Proxy :< Proxy :< Proxy :< PNil
Но я в том случае, когда мне нужно сделать "полиморфную" функцию для всех as
... но GHC это не нравится.
asProds :: forall as. Proxy as -> Prod Proxy as
asProds _ = known :: Prod Proxy as
Выходит с этой ошибкой:
No instance for (Known (Prod f) as)
arising from a use of 'known'
Что, я думаю, говорит о том, что GHC не может показать, что будет экземпляр, который он выберет, который будет работать для любого as
, или у него нет стратегии создания known
для этого экземпляра.
Я, как человек, знаю, что это так, но есть ли способ заставить это работать? Все экземпляры находятся "в рамках" и доступны... но как я могу сказать GHC, как сконструировать его таким образом, чтобы он был удовлетворен?