Возможно ли иметь связанный синоним типа с переменными, не упомянутыми в классе type?

#haskell #types

#haskell #типы

Вопрос:

В синонимах связанного типа (Чакраварти, Келлер, Джонс) в документе, по-видимому, указывается, что допустимо следующее:

 class C a where
  type S a (k :: * -> *) :: *
  

Однако, когда я пытаюсь запустить это, я получаю ошибку компилятора (с -XTypeFamilies ):

 Not in scope: type variable `k'
  

Я что-то упускаю, или фактическая реализация в GHC не совпадает с тем, что упоминается в документе?

Комментарии:

1. Теперь я нашел hackage.haskell.org/trac/ghc/ticket/3714 который для меня читается так, как будто это невозможно сделать. Если это правильно, пожалуйста, не стесняйтесь отвечать этим.

Ответ №1:

Как вы уже выяснили, это невозможно в GHC:

Точно так же, как и в случае объявления связанных данных, именованные параметры типа должны быть перестановкой подмножества параметров класса. Примеры

 class C a b c where { type T c a :: * }   -- OK
class D a where { type T a x :: * }       -- No: x is not a class parameter
class D a where { type T a :: * -> * }    -- OK
  

Тикет, на который вы ссылались, на самом деле объясняет причину невозможности определить что-то вроде S . Это работает, если вы делаете это следующим образом:

 class C a where
    type S a :: (* -> *) -> *
data TupK a k = TupK (a, k a)
instance C [a] where
    type S [a] = TupK a
  

Однако теперь вы застряли с новым типом данных. Использование синонимов типов не будет работать («Синоним типа `TupK’ должен иметь 2 аргумента»), и добавление дополнительных параметров к S не поможет («Количество параметров должно соответствовать объявлению семейства; ожидается 1»), как задокументировано в заявке.

Комментарии:

1. @ocharles Я бы добавил, что вам не обязательно использовать связанный тип. Вы вполне могли бы сделать что-то вроде type family S a (k :: * -> *); class C a where foo :: S a [] -> Int . Основное преимущество связанных типов заключается в том, что компилятору легче выдавать исправные сообщения об ошибках (и более удобный синтаксис для объявления экземпляров типа).

2. Да, на данный момент я разделил 2, но было приятно соединить их

Ответ №2:

Нет, но вы можете использовать менее мощный:

 class C a where
  type S a :: (k :: * -> *) -> *
  

… который мог бы служить той же цели, если вам не нужна дополнительная мощность.