Spec-Zone.ru › Haskell 9

6.6.3. Отдельные объявления deriving

StandaloneDeriving
Начиная с:

6.8.1

Статус:

Включено в GHC2024, GHC2021

Разрешает использовать отдельные объявления deriving.

GHC разрешает отдельные объявления deriving, включаемые с помощью StandaloneDeriving:

data Foo a = Bar a | Baz String

deriving instance Eq a => Eq (Foo a)

Синтаксис идентичен синтаксису обычного объявления экземпляра, за исключением (a) ключевого слова deriving и (b) отсутствия части where.

Однако отдельный вывод экземпляров имеет несколько важных отличий от предложения deriving:

  • Отдельное объявление вывода экземпляра не обязательно должно находиться в том же модуле, что и объявление типа данных. (Но учитывайте опасность осиротевших экземпляров (Осиротевшие модули и объявления экземпляров).
  • В большинстве случаев необходимо явно указать контекст (в примере это (Eq a)), точно так же, как в обычном объявлении экземпляра. (В отличие от этого, в предложении deriving, присоединённом к объявлению типа данных, контекст выводится автоматически.)

    Исключение из этого правила: контекст отдельного объявления вывода экземпляра может быть выведен автоматически, если в качестве контекста используется единственное ограничение с дополнительным шаблоном wildcard, например:

    deriving instance _ => Eq (Foo a)
    

    По сути, это то же самое, как если бы вы написали deriving Eq после объявления data Foo a. Для использования этой возможности требуется расширение PartialTypeSignatures (Частичные сигнатуры типов).

  • В отличие от объявления deriving, присоединённого к объявлению data, экземпляр может быть более конкретным, чем тип данных (при условии, что вы также используете FlexibleInstances, Правила завершения для экземпляров). Например:

    data Foo a = Bar a | Baz String
    
    deriving instance Eq a => Eq (Foo [a])
    deriving instance Eq a => Eq (Foo (Maybe a))
    

    Это создаст выведенный экземпляр для (Foo [a]) и (Foo (Maybe a)), но другие типы, например (Foo (Int,Bool)), не будут экземплярами Eq.

  • В отличие от объявления deriving, присоединённого к объявлению data, GHC не ограничивает форму типа данных. Вместо этого GHC просто генерирует соответствующий шаблонный код для указанного класса и проверяет его тип. Если возникает ошибка типа, это ваша проблема. (Если в коде есть ошибка типа, GHC покажет проблемный фрагмент.)

    Преимущество этого подхода в том, что можно выводить экземпляры для GADT и других необычных типов данных, если только шаблонный код действительно проходит проверку типов. Например:

    data T a where
       T1 :: T Int
       T2 :: T Bool
    
    deriving instance Show (T a)
    

    В этом примере нельзя написать ... deriving( Show ) в объявлении типа данных для T, потому что T — это GADT, но можно сгенерировать объявление экземпляра с помощью отдельного вывода экземпляров.

    Недостаток в том, что, если шаблонный код не пройдёт проверку типов, вы получите сообщение об ошибке в этом коде, который вы не писали. При использовании предложения deriving условия применения неизбежно более консервативны, зато сообщения об ошибках могут быть понятнее.

  • В большинстве случаев нельзя использовать отдельный вывод экземпляров для создания экземпляра типа данных, если не все его конструкторы находятся в области видимости. Это связано с тем, что выведенный экземпляр будет содержать код, использующий конструкторы скрытым образом, что нарушит абстракцию.

    Единственное исключение из этого правила — DeriveAnyClass, поскольку вывод экземпляра с помощью DeriveAnyClass просто создаёт пустое объявление экземпляра, для которого не требуется использовать конструкторы. Подробнее см. раздел вывод экземпляров любого класса.

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

  • Объявление deriving instance должно подчиняться тем же правилам формы и завершения, что и обычные объявления экземпляров; эти правила управляются теми же флагами. См. Объявления и разрешение экземпляров.
  • Отдельный синтаксис обобщается для newtype точно так же, как обобщаются обычные предложения deriving (Обобщённые выведенные экземпляры для newtype). Например:

    newtype Foo a = MkFoo (State Int a)
    
    deriving instance MonadState Int Foo
    

    GHC всегда считает последний параметр экземпляра (Foo в этом примере) типом, для которого выводится экземпляр.

© 2002–2007 The University Court of the University of Glasgow. All rights reserved.
Licensed under the Glasgow Haskell Compiler License.
https://downloads.haskell.org/~ghc/9.14.1/docs/users_guide/exts/standalone_deriving.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API