#haskell #ghc #type-kinds
#haskell #ghc #тип-виды
Вопрос:
Допустим, у меня есть полиморфный тип, где одним из параметров является тип с более высоким типом ( * -> *
) .
data Tricky m = Tricky { numbers :: m Int, genesis :: m String }
Существует ли общий способ получения экземпляров для таких типов без использования тайных и небезопасных языковых расширений?
Я попытался включить StandaloneDeriving
, чтобы я мог указать контекст:
deriving instance Show (m Int) => Show (Tricky m)
Но затем GHC жалуется на то, что ограничение не меньше, чем заголовок экземпляра, и указывает мне в направлении UndecidableInstances
.
Подводя итог:
1. Должен ли я просто согласиться с этим советом или есть лучший способ?
2. Есть ли какие-либо предложения по упрощению этого процесса?
3. Является ли каким-то неправильным желанием создавать экземпляры с более высоким типом? Было бы лучше вместо этого создавать экземпляры для нескольких конкретных типов (например, Vector
, []
, Set
)
Ответ №1:
1. В этом нет ничего небезопасного UndecidableInstances
.
Есть еще один способ определения Show (Tricky m)
, который заключается в том, чтобы требовать m
удовлетворения forall a. Show a => Show (m a)
. Это фиксируется классом типов, например
class Show1 f where
showsPrec1 :: Show a => Int -> f a -> ShowS
В базу 4.9 добавлена еще более умная версия Show1
. Он более общий, поскольку его можно использовать для отображения m a
, когда a
у него нет Show a
экземпляра.
2. Вы нашли правильные фрагменты для этого.
3. Нет, правильно абстрагироваться от еще более высоких структур, таких как Vector
, []
, и Set
. Преобразователи монад имеют вид (* -> *) -> (* -> *)
и абстракцию над типами вида (* -> *)
, того же типа, что и функтор, для создания типов с тем же типом, что и функтор. Tricky
имеет вид (* -> *) -> *
, он принимает что-то с тем же видом, что и функтор, и создает обычный тип данных. Я называю типы данных такого рода «Моделями», поскольку они создают тип данных, абстрагирующийся от того, как он составлен.