DeriveAnyClass против пустого экземпляра - PullRequest
2 голосов
/ 14 июня 2019

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

type family IsRecord (a :: Type) where
  ...

Теперь у меня есть этот класс типов, который имеет методы с реализациями по умолчанию, но требует, чтобы тип был записью, добавив ограничение IsRecord:

class IsRecord a => Foo a where
  foo :: Text
  foo = "foo"

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

data Bar = Bar

instance Foo Bar   -- error: Bar is not a record

Но если я включу -XDeriveAnyClass и добавлю его в производное предложение, его не скомпилируют, полностью игнорируя ограничение:

data Bar = Bar
  deriving (Foo)

Я понимаю, что DeriveAnyClass генерирует пустое объявление экземпляра, что я и делаю в первом примере, но все равно оно не выдает ошибку. Что происходит?

Я использую GHC 8.6.4

1 Ответ

1 голос
/ 14 июня 2019

Вау! Я собирался отметить это как дубликат В чем разница между DeriveAnyClass и пустым экземпляром? , но, похоже, поведение GHC изменилось с тех пор, как на этот вопрос был задан и дан ответ!

В любом случае, если вы спросите - либо с :i внутри ghci, либо с -ddump-deriv перед запуском ghci - что сделал компилятор, ясно, какая разница в вашем случае:

> :i Bar
data Bar = Bar  -- Defined at test.hs:15:1
instance IsRecord Bar => Foo Bar -- Defined at test.hs:16:13

В самом деле, если вы измените не-1011 * версию своего кода для соответствия, выведите

instance IsRecord Bar => Foo Bar

вместо

instance Foo Bar

все отлично работает. Детали того, как этот экземпляр контекста был выбран, кажутся немного сложными; Вы можете прочитать, что руководство GHC должно сказать об этом здесь , хотя я подозреваю, что описание там либо не совсем точное, либо не полное, так как я не получаю тот же ответ, который компилятор делает здесь, если я Строго соблюдайте правила, изложенные в документации. (Я подозреваю, что ответ true заключается в том, что сначала он записывает экземпляр, а затем просто выполняет обычные операции вывода типа и копирует любые ограничения, которые он обнаруживает таким образом, в контекст экземпляра.)

...