Продвижение конструктора данных в GHC-7.6

У меня был этот код:

class SymbolSet tpe where
  data Symbol tpe :: *

data SSet tpe where
  Identity :: tpe -> SSet tpe
  And :: SSet tpe -> Symbol tpe -> SSet tpe

class HasElem a b where

instance (SymbolSet tpe) => HasElem (And (Identity tpe) s) s
instance (HasElem sset s) => HasElem (And sset s) s

который компилируется в GHC-7.4. Однако при переходе на GHC-7.6 он начал давать ошибки компиляции:

'And' of tpe `forall tpe. tpe -> Symbol * tpe -> SSet tpe' is not promotable

при перекопах через документы я нашел новое предложение, добавленное в страницы "Datatype Promotion" в GHC-7.6 vs GHC-7.4

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

Мой вопрос:

  • В чем причина не поощрения таких конструкторов?
  • Каким будет правильный способ сделать это?

Ответ 1

Вы не сказали, какую версию GHC 7.6 вы использовали или включаете в себя расширения, которые у вас есть, поэтому я немного догадываюсь.

Этот билет, кажется, отвечает на ваш вопрос 1, хотя я сам не полностью понимаю проблему. В вашем конкретном примере я думаю, что SSet не поддерживается, потому что один из его аргументов (Symbol tpe) является ассоциированным типом, который приносит с собой ограничение SymbolSet.

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

{-# LANGUAGE DataKinds , TypeFamilies , GADTs , MultiParamTypeClasses #-}
class SymbolSet tpe where
  -- data Symbol tpe :: *
data Symbol tpe :: *
-- ...

Я могу заставить весь shebang скомпилировать, добавив добрые подписи в HasElem:

{-# LANGUAGE DataKinds , TypeFamilies , GADTs , MultiParamTypeClasses, FlexibleInstances  #-}
class SymbolSet tpe where
-- MOVED OUT OF CLASS:
data Symbol tpe :: *

data SSet tpe where
  Identity :: tpe -> SSet tpe
  And :: SSet tpe -> Symbol tpe -> SSet tpe

-- ADDED KIND SIGNATURES:
class HasElem (a :: SSet *) (b :: Symbol *) where

instance (SymbolSet tpe) => HasElem (And (Identity tpe) s) s
instance (HasElem sset s) => HasElem (And sset s) s

Я действительно не понимаю ваш код, чтобы он не работал для вас.