Spec-Zone.ru › Haskell 9

6.11.7. Частичные типы сигнатур

PartialTypeSignatures
С тех пор:

7.10.1

Проверяющий типов позволит выводить типы для дыр.

Частичная сигнатура типа — это сигнатура типа, содержащая специальные заполнительные символы, называемые подстановочными знаками. Подстановочный знак записывается как нижнее подчеркивание (например, «_») или, если включен NamedWildCards, любой идентификатор с ведущим нижним подчеркиванием (например, «_foo», «_bar»). Частичные сигнатуры типов относятся к сигнатурам типов так же, как Типизированные дыры относятся к выражениям. Во время компиляции эти подстановочные знаки или дыры будут генерировать сообщение об ошибке, которое описывает, какой тип был выведен в позиции дыры, и информацию об источнике любых свободных переменных типа. GHC по умолчанию сообщает такие сообщения об ошибках.

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

По умолчанию проверяющий типов будет сообщать сообщение об ошибке для каждой дыры в частичной сигнатуре типа, информируя программиста о выведенном типе. Когда включен PartialTypeSignatures расширение, проверяющий типов будет принимать выведенный тип для каждой дыры, генерируя предупреждения вместо ошибок. Кроме того, эти предупреждения можно отключить с помощью -Wno-partial-type-signatures флаг.

Однако, поскольку GHC должен вывести тип, когда часть типа пропущена, он не может использовать полиморфную рекурсию. То же ограничение применяется, когда сигнатура типа полностью пропущена.

Частичная сигнатура типа также заставляет GHC обобщать привязку, даже если MonoLocalBinds включен; см. Обобщение let.

6.11.7.1. Синтаксис

Полная (частичная) сигнатура типа имеет следующий вид: forall a b .. . (C1, C2, ..) => tau. Она состоит из трех частей:

  • Переменные типа: a b ..
  • Ограничения: (C1, C2, ..)
  • Тип (монотип): tau

Мы различаем три типа подстановочных знаков.

6.11.7.1.1. Подстановочные знаки типа

Подстановочные знаки, встречающиеся в части монотипа (тау) сигнатуры типа, являются подстановочными знаками типа («тип» часто опускается, так как это по умолчанию вид подстановочного знака). Подстановочные знаки типа могут быть привязаны к любому монотипу, такому как Bool или Maybe [Bool], включая функции и типы высшего уровня, такие как (Int -> Bool) или Maybe.

not' :: Bool -> _
not' x = not x
-- Inferred: Bool -> Bool

maybools :: _
maybools = Just [True]
-- Inferred: Maybe [Bool]

just1 :: _ Int
just1 = Just 1
-- Inferred: Maybe Int

filterInt :: _ -> _ -> [Int]
filterInt = filter -- has type forall a. (a -> Bool) -> [a] -> [a]
-- Inferred: (Int -> Bool) -> [Int] -> [Int]

Например, первый подстановочный знак в сигнатуре типа not' выведет следующее сообщение об ошибке:

Test.hs:4:17: error:
    • Found type wildcard ‘_’ standing for ‘Bool’
      To use the inferred type, enable PartialTypeSignatures
    • In the type signature:
        not' :: Bool -> _
    • Relevant bindings include
        not' :: Bool -> Bool (bound at Test.hs:5:1)

Когда подстановочный знак не привязан к монотипу, он будет обобщен, т.е. заменен новой переменной типа, например

foo :: _ -> _
foo x = x
-- Inferred: forall t. t -> t

filter' :: _
filter' = filter -- has type forall a. (a -> Bool) -> [a] -> [a]
-- Inferred: (a -> Bool) -> [a] -> [a]

6.11.7.1.2. Именованные подстановочные знаки

NamedWildCards
С тех пор:

7.10.1

Статус:

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

Разрешить именование подстановочных знаков (например, _x). в сигнатурах типов.

Подстановочные знаки типа также могут быть именованы, присваивая подчеркиванию идентификатор в качестве суффикса, т. е. _a. Эти подстановочные знаки называются именованными подстановочными знаками. Все вхождения одного и того же именованного подстановочного знака в одной сигнатуре типа будут объединены в один тип. Например:

f :: _x -> _x
f ('c', y) = ('d', error "Urk")
-- Inferred: forall t. (Char, t) -> (Char, t)

Именованный подстановочный знак заставляет аргумент и типы результатов быть одинаковыми. Без сигнатуры GHC вывел бы forall a b. (Char, a) -> (Char, b). Именованный подстановочный знак может упоминаться в ограничениях, при условии, что он также встречается в части монотипа сигнатуры типа, чтобы убедиться, что он объединяется с чем-то:

somethingShowable :: Show _x => _x -> _
somethingShowable x = show x
-- Inferred type: Show a => a -> String

somethingShowable' :: Show _x => _x -> _
somethingShowable' x = show (not x)
-- Inferred type: Bool -> String

Помимо подстановочного знака дополнительных ограничений (см. Дополнительный подстановочный знак ограничений), только именованные подстановочные знаки могут встречаться в ограничениях, например, _x в Show _x.

Если ScopedTypeVariables включен, именованные подстановочные знаки сигнатуры функции охватывают тело функции, как и явно объявленные переменные типа (Лексически-скопированные переменные типа), хотя явного forall нет. Например:

f :: _a -> _a
f x = let g :: _a -> _a
          g = ...
      in ...

Здесь именованный подстановочный знак _a охватывает тело f, тем самым связывая вхождения _a в сигнатуре g. Все четыре вхождения означают один и тот же тип.

Именованные подстановочные знаки не следует путать с переменными типа. Несмотря на синтаксическое сходство, именованные подстановочные знаки могут объединяться с монотипами, а также обобщаться (и вести себя как переменные типа).

В первом примере выше, _x обобщается (и фактически заменяется новой переменной типа a). Во втором примере, _x объединяется с типом Bool, и поскольку Bool реализует класс типов Show, ограничение Show Bool может быть упрощено.

По умолчанию GHC (как предписывает стандарт Haskell 2010) интерпретирует идентификаторы, начинающиеся с нижнего подчеркивания в типе, как переменные типа. Чтобы обработать их как именованные подстановочные знаки, следует включить NamedWildCards расширение. Пример ниже продемонстрировал эффект.

foo :: _a -> _a
foo _ = False

Компиляция этой программы без включения NamedWildCards генерирует сообщение об ошибке, которое жалуется на переменную типа _a не соответствует фактическому типу Bool.

Test.hs:5:9: error:
    • Couldn't match expected type ‘_a’ with actual type ‘Bool’
      ‘_a’ is a rigid type variable bound by
        the type signature for:
          foo :: forall _a. _a -> _a
        at Test.hs:4:8
    • In the expression: False
      In an equation for ‘foo’: foo _ = False
    • Relevant bindings include foo :: _a -> _a (bound at Test.hs:5:1)

Компиляция этой программы с включенными NamedWildCards (а также PartialTypeSignatures) расширением генерирует следующее сообщение об ошибке, которое сообщает о выведенном типе именованного подстановочного знака _a.

Test.hs:4:8: warning: [-Wpartial-type-signatures]
    • Found type wildcard ‘_a’ standing for ‘Bool’
    • In the type signature:
        foo :: _a -> _a
    • Relevant bindings include
        foo :: Bool -> Bool (bound at Test.hs:5:1)

6.11.7.1.3. Подстановочный знак дополнительных ограничений

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

arbitCs :: _ => a -> String
arbitCs x = show (succ x) ++ show (x == x)
-- Inferred:
--   forall a. (Enum a, Eq a, Show a) => a -> String
-- Error:
Test.hs:5:12: error:
    Found constraint wildcard ‘_’ standing for ‘(Show a, Eq a, Enum a)’
    To use the inferred type, enable PartialTypeSignatures
    In the type signature:
      arbitCs :: _ => a -> String

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

-- Also a correct partial type signature:
arbitCs' :: (Enum a, _) => a -> String
arbitCs' x = arbitCs x
-- Inferred:
--   forall a. (Enum a, Show a, Eq a) => a -> String
-- Error:
Test.hs:9:22: error:
    Found constraint wildcard ‘_’ standing for ‘()’
    To use the inferred type, enable PartialTypeSignatures
    In the type signature:
      arbitCs' :: (Enum a, _) => a -> String

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

noCs :: _ => String
noCs = "noCs"
-- Inferred: String
-- Error:
Test.hs:13:9: error:
    Found constraint wildcard ‘_’ standing for ‘()’
    To use the inferred type, enable PartialTypeSignatures
    In the type signature:
      noCs :: _ => String

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

Именованные подстановочные знаки дополнительных ограничений не поддерживаются.

6.11.7.2. Где они могут использоваться?

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

{-# LANGUAGE ScopedTypeVariables #-}
foo :: _
foo (x :: _) = (x :: _)
-- Inferred: forall w_. w_ -> w_

Анонимные и именованные символы подстановки могут появляться в левой части объявления типа или экземпляра данных; см. Символы подстановки в левой части экземпляров данных и типов семейств.

Анонимные символы подстановки также разрешены в видимых применениях типов/видимых применениях видов (Видимое применение типа). Если вы хотите указать только второй аргумент типа для wurble, то вы можете сказать wurble @_ @Int , где первый аргумент является символом подстановки.

Самостоятельные deriving объявления позволяют использовать один символ подстановки дополнительных ограничений, как в этом примере:

deriving instance _ => Eq (Foo a)

Это обозначает производный Eq (Foo a) экземпляр, где контекст выводится аналогично тому, как это делают обычные deriving клаузы. Любое другое использование символов подстановки в самостоятельном deriving объявлении запрещено.

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

class C _ where ...          -- Illegal
instance Eq (T _)            -- Illegal (currently; would actually make sense)
instance Eq _a => Eq (T _a)  -- Perfectly fine, same as  Eq a => Eq (T a)

Частичные типы сигнатур также могут использоваться в Template Haskell вставках.

  • Вставки объявлений: частичные типы сигнатур полностью поддерживаются.

    {-# LANGUAGE TemplateHaskell, NamedWildCards #-}
    $( [d| foo :: _ => _a -> _a -> _
           foo x y = x == y|] )
    
  • Вставки выражений: анонимные и именованные символы подстановки могут использоваться в сигнатурах выражений. Символы подстановки дополнительных ограничений не поддерживаются, как и в обычных сигнатурах выражений.

    {-# LANGUAGE TemplateHaskell, NamedWildCards #-}
    $( [e| foo = (Just True :: _m _) |] )
    
  • Вставки выражений с типом: поддерживаются те же символы подстановки, что и в (нетипизированных) вставках выражений.
  • Вставки шаблонов: анонимные и именованные символы подстановки могут использоваться в сигнатурах шаблонов. Обратите внимание, что ScopedTypeVariables должен быть включен, чтобы разрешить сигнатуры шаблонов. Символы подстановки дополнительных ограничений не поддерживаются, как и в обычных сигнатурах шаблонов.

    {-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
    foo $( [p| (x :: _) |] ) = x
    
  • Вставки типов: в вставках типов поддерживаются только анонимные символы подстановки. Именованные и символы подстановки дополнительных ограничений не поддерживаются.

    {-# LANGUAGE TemplateHaskell #-}
    foo :: $( [t| _ |] ) -> a
    foo x = x
    

© 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.12.1/docs/users_guide/exts/partial_type_signatures.html

Spec-Zone.ru

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