Haskell: определения экземпляров для семейств типов

Допустим, у нас есть следующий код:

class C t where
  g :: t

instance C Int where
  g = 42

Просто. Мы также можем определить функции на Int, например, так:

f1 :: Int -> Int
f1 x = x * x

Я работал с семействами типов, в частности, потому что Data.Has использует их, и я хочу вставить их в IxSet,

Но здесь я собираюсь представить упрощенный пример. Допустим, мы хотим определить новый тип X, что похоже на Int. Мы могли бы сделать это:

type family X
type instance X = Int

Затем мы можем определить функции на X вот так:

f2 :: X -> X
f2 x = x * x + 1

Пока проблем нет. Теперь давайте попробуем определить экземпляр C X как мы сделали для C Int:

instance C X where
  g = 43

Ой, теперь у нас есть следующая ошибка:

Приложение семейства синонимов недопустимого типа в экземпляре: X
В объявлении экземпляра для 'C X'

Теперь давайте попробуем что-то немного другое:

newtype NewX = NewX X

instance C NewX where
  g = 43

Теперь у нас есть другая ошибка, а именно:

Нет экземпляра для (Num NewX)
вытекающие из буквального '43'

Кажется, что newtype Ключевое слово исключает любую информацию о том, к каким классам принадлежал предыдущий класс. Тем не менее, кажется, что я не могу избежать newtype, так как я не могу использовать семейства типов в определениях экземпляров.

Есть ли лучший способ сделать это без необходимости перезаписывать определения экземпляров дополнительными явными упоминаниями экземпляров, которые в противном случае были бы выведены?


Исходная информация:

Причина, по которой мне нужно это работать, заключается в следующем:

import Data.Has
import Data.IxSet

data Col1 = Col1; type instance TypeOf Col1 = Text
data Col2 = Col2; type instance TypeOf Col2 = Text

type Row = FieldOf Col1 :&: FieldOf Col2;

instance Indexable Row where
  empty = ixSet [ixFun $ (\x -> [ Col1 ^. x ]) ] -- Maybe add some more indexes later

Это не с:

Приложение семейства синонимов недопустимого типа в экземпляре: Row
В объявлении экземпляра для 'Indexable Row'

Изготовление Row newtype вызывает следующую ошибку:

Нет экземпляра для (Содержит (Помеченный Col1 Text) Строка), возникающего из-за использования `^.' Возможное исправление: добавьте объявление экземпляра для строки (Содержит (текст с меткой Col1))

Единственный способ, которым я могу обойти это, - это добавить длинное производное предложение следующим образом:

newtype Row = Row (FieldOf Col1 :&: FieldOf Col2)
  deriving 
  (
    Contains (Labelled Col1 Text), -- Add this for every column
    Contains (Labelled Col2 Text)  -- ...
  )

Даже то, что позволяет мне "typedef" Contains (Labelled x (TypeOf x)) сказать HasCol x было бы полезно.

2 ответа

Решение

newtype делает это - он определяет новый тип, в то время как type определяет синоним. Если вам не нравится куча производных предложений, всегда можно использовать изоморфизм с базовым типом

instance C NewX where
   g = NewX  43

Причина, по которой синонимы типов не очень хорошо подходят для объявлений Instance, заключается в том, что функции (включая функции типов) работают только в одном направлении. Вы можете только сопоставить шаблон с конструкторами, поэтому newtype позволяет вводить конструктор нового типа при нулевых затратах времени выполнения. В твоей проблеме почему нет

newtype Row = Row {runRow :: FieldOf Col1 :&: FieldOf Col2}

instance Indexable Row where
  empty = ixSet [ixFun $ (\x -> [ Col1 ^. (runRow x) ]) ]

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


Изменить (вопрос задающий):

А еще лучше, нет необходимости даже менять тип данных Row

newtype Row = Row ( FieldOf Col1 :&: FieldOf Col2 )

instance Indexable Row where
  empty = ixSet [ixFun $ (\(Row x) -> [ Col1 ^. x ]) ]

Следующий файл компилируется здесь:

{-# LANGUAGE GeneralizedNewtypeDeriving, TypeFamilies #-}

class C a where g :: a
type family X
type instance X = Int
newtype NewX = NewX X deriving Num
instance C NewX where g = 43
Другие вопросы по тегам