Spec-Zone.ru › Haskell 9

6.5.6. Выборчики полей

FieldSelectors
С момента:

9.2.1

Статус:

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

Делает функции-выборчики полей записей видимыми в выражениях.

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

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

Метки полей по-прежнему могут использоваться при построении записей, их обновлении и сопоставлении с образцом.

Например, при определении типа данных

data Foo = MkFoo { bar :: Int, baz :: String }

Будут доступны:

  1. конструктор типа Foo;
  2. конструктор данных MkFoo;
  3. поля bar и baz для построения, обновления и сопоставления с образцом записей; и
  4. функции-выборчики bar :: Foo -> Int и baz :: Foo -> String.

Если расширение NoFieldSelectors включено в месте определения типа данных, элементы (1), (2) и (3) по-прежнему будут доступны, но (4) – нет. Соответственно, разрешается объявлять глобальную привязку с тем же именем, что и поле, а использование этого имени в выражении однозначно относится к не-полю. Например, разрешается следующее:

data Foo = MkFoo { bar :: Int, baz :: String }
bar = ()  -- does not conflict with `bar` field
baz = bar -- unambiguously refers to `bar` the unit value, not the field

Если у вас есть несколько типов данных с одинаковым именем поля, вам нужно включить DuplicateRecordFields, чтобы разрешить их одновременное объявление. Никогда не разрешается объявлять в одном модуле несколько глобальных привязок с одинаковым именем.

Расширение DisambiguateRecordFields (подразумеваемое расширением DuplicateRecordFields) полезно в сочетании с NoFieldSelectors, поскольку оно исключает не-поля из рассмотрения при разрешении имён полей при построении, обновлении и сопоставлении с образцом записей.

6.5.6.1. Импорт и экспорт функций-выборчиков

При FieldSelectors, эти модули эквивалентны:

module A (Foo(MkFoo, bar, baz)) where
  data Foo = MkFoo { bar :: Int, baz :: Int }

module B (Foo(MkFoo, bar), baz) where
  data Foo = MkFoo { bar :: Int, baz :: Int }

При NoFieldSelectors, эти два оператора экспорта теперь отличаются. Первый экспортирует поле baz, но не глобальную привязку baz, в то время как второй экспортирует глобальную привязку baz (если она определена), но не поле baz.

Из-за этого изменения использование NoFieldSelectors и явное указание функций-выборчиков отличается от использования FieldSelectors: в первом случае поля и функции должны экспортироваться отдельно. Например, здесь функции-выборчики не экспортируются:

{-# LANGUAGE NoFieldSelectors #-}
module M (Foo(MkFoo, bar, baz)) where
  data Foo = MkFoo { bar :: Int, baz :: Int }

  bar (MkFoo x _) = x
  baz (MkFoo _ x) = x

в то время как здесь функции-выборчики экспортируются:

{-# LANGUAGE FieldSelectors #-}
module M (Foo(MkFoo, bar, baz)) where
  data Foo = MkFoo { bar :: Int, baz :: Int }

Дикий экспорт экспортирует метки полей, но не экспортирует глобальную привязку, которая случайна имеет то же имя. В приведённых выше примерах экспорт Foo(..) эквивалентен экспорту Foo(MkFoo, bar, baz).

© 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/field_selectors.html

Spec-Zone.ru

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