Как я могу заставить GHC генерировать экземпляры Data.Typeable для GADT с Typeable в контексте?

Предположим, у меня есть следующий код:

{-# LANGUAGE GADTs, DeriveDataTypeable, StandaloneDeriving #-}
import Data.Typeable

class Eq t => OnlyEq t
class (Eq t, Typeable t) => BothEqAndTypeable t

data Wrapper a where
    Wrap :: BothEqAndTypeable a => a -> Wrapper a

deriving instance Eq (Wrapper a)
deriving instance Typeable1 Wrapper

Затем работает следующее объявление экземпляра без ограничения на t:

instance OnlyEq (Wrapper t)

и делает то, что я от него ожидаю.


Но следующее объявление экземпляра не работает:

instance BothEqAndTypeable (Wrapper t)

поскольку GHC - я использую 7.6.1 - жалуется, что:

No instance for (Typeable t)
  arising from the superclasses of an instance declaration
Possible fix:
  add (Typeable t) to the context of the instance declaration
In the instance declaration for `BothEqAndTypeable (Wrapper t)'

Конечно, добавление Typeable t в контекст работает. Но так же добавляется следующий экземпляр:

instance Typeable (Wrapper t) where
    typeOf (Wrap x) = typeOf1 (Wrap x) `mkAppTy` typeOf x

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

Я надеялся, что GHC сможет извлечь ограничение Typeable из контекста конструктора Wrap, как это было с ограничением Eq. Я думаю, что мои проблемы сводятся к тому, что GHC явно запрещает писать deriving instance Typeable (Wrapper t), а стандартный (Typeable1 s, Typeable a) => Typeable (s a) экземпляр не может «заглянуть внутрь» s a, чтобы найти Typeable a словарь.


person yatima2975    schedule 20.03.2013    source источник


Ответы (1)


Я надеялся, что GHC сможет извлечь ограничение Typeable из контекста конструктора Wrap

Если бы у него был Wrap конструктор, он мог бы вытащить из него Typeable ограничение.

Но у него нет Wrap конструктора.

Разница в том, что экземпляр Eq использует это значение, так что либо Wrap something, где конструктор Wrap делает доступным словарь Eq для обернутого типа, и все в порядке, либо это , и тогда все тоже хорошо, оценивая x == y дно вне.

Обратите внимание, что производные

instance Eq (Wrapper a)

нет ограничения Eq на переменную типа a.

Prelude DerivT> (undefined :: Wrapper (Int -> Int)) == undefined
*** Exception: Prelude.undefined
Prelude DerivT> (undefined :: (Int -> Int)) == undefined

<interactive>:3:29:
    No instance for (Eq (Int -> Int)) arising from a use of `=='
    Possible fix: add an instance declaration for (Eq (Int -> Int))
    In the expression: (undefined :: Int -> Int) == undefined
    In an equation for `it':
        it = (undefined :: Int -> Int) == undefined

Но экземпляр Typeable не должен использовать значение, поэтому нижнего предела не будет, если предоставленное значение не равно Wrap something.

Таким образом, производные instance Typeable1 Wrapper поставляют

instance Typeable t => Typeable (Wrapper t)

но не безудержный

instance Typeable (Wrapper t)

и этот неограниченный экземпляр не может быть получен GHC.

Следовательно, вы должны либо предоставить ограниченный

instance Typeable t => BothEqAndTypeable (Wrapper t)

или неограниченный

instance Typeable (Wrapper t)

себя.

person Daniel Fischer    schedule 20.03.2013
comment
Правильно, я все время забываю о тонкостях undefined, поскольку я обычно храню что-то в своих типах данных :-) Тогда я думаю, что мне нужны какие-то newtype GADT! И дополнительный вопрос, если можно: является ли неограниченный Typeable (Wrapper t) экземпляр, который я написал, плохим, при условии, что мне все равно, что typeOf (error "aargh" :: Wrapper Bool) достигнет дна? - person yatima2975; 21.03.2013
comment
Что ж, это немного удивительный экземпляр, поскольку вы не можете использовать его с undefined :: Wrapper Bool, как с другими Typeable экземплярами. Если вы сделаете это достоянием общественности, по крайней мере, сделайте предупреждение. Но я не думаю, что это обязательно должно вас останавливать. Однако в будущих выпусках GHC - я думаю, начиная с 7.8 и далее, все Typeable экземпляры будут предоставляться GHC, а для всех типов - iirc. Так что тогда вам не придется сталкиваться с такими проблемами. - person Daniel Fischer; 21.03.2013
comment
Глядя в репозиторий, вам понадобится -XAutoDeriveTypeable. Прохладный! Я думаю, что мог бы просто пойти и клонировать 7.8.1 на выходных для этого, но в последний раз я создавал GHC в 2002 году (начало цикла 6.x?), Так что это немного пугает .. Но еще раз спасибо! - person yatima2975; 21.03.2013