название этого, по общему признанию, не очень описательное, но я не знаю, как еще описать это в коротком заголовке. Буду признателен за любые рекомендации!Вывод обычного экземпляра typeclass из серии меньших?
Я буду представлять очень упрощенную версию моего вопроса :)
Так у меня есть класс типов
class Known f a where
known :: f a
, который должен быть в состоянии произвести каноническое построение заданного тип по определенному индексу, полезный для работы с GADT и т. д. Я даю упрощенную версию this с соответствующими деталями.
Так что, очевидно, пример для Proxy
:
instance Known Proxy a where
known = Proxy
Что мы можем использовать:
> known :: Proxy Monad
Proxy
Но есть также экземпляр для this HList-like type:
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)
кортеж. Тот же Functor, разные типы.
Запись экземпляра прилично проста:
instance Known (Prod f) '[] where
known = PNil
instance (Known f a, Known (Prod f) as) => Known (Prod f) (a ': as) where
known = known :< known
Который работает довольно хорошо: (предполагая Показать экземпляр)
> 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, как его построить так, как это выполняется?
Ах. К сожалению, избежать такого ограничения является причина, по которой я это переживаю в первую очередь. Но! Первоначально моя проблема заключалась в том, что мне нужно было указать «(Аппликативные (Foo ns), Foldable (Foo ns)) и т. Д. Для всех моих экзистенциальных элементов, и я думал, что только это позволит избавиться от всего этого. Но теперь я вижу, что могу просто заменить все эти различные ограничения на ограничение «Известный». Не избегайте ограничений, но теперь только один улов - все намного чище, спасибо! –
@JustinL. Вы также можете использовать [синтаксисы ограничения] (https://downloads.haskell.org/~ghc/7.8.4/docs/html/users_guide/constraint-kind.html): 'type Known ns = (Applicative (Foo ns) , Foldable (Foo ns), ...) '. –
@ AlexeyRomanov он по-прежнему чувствует себя очень ad-hoc и un-haskell для меня. Я могу бросить кучу экземпляров, которые имеют очень редкие/необычные и неясные способы использования, которые не имеют никакого бизнеса, принадлежащего фактическому конструктору данных для типа ... он не имеет ничего общего с неясными классами в все. И мне придется добавлять класс и дублировать работу каждый раз, когда я пишу новый экземпляр. –