-
FieldSelectors -
- Версия:
-
9.2.1
- Статус:
-
Включено в
GHC2024,GHC2021,Haskell2010,Haskell98
Делает функции-селекторы полей записи доступными в выражениях.
По умолчанию расширение FieldSelectors включено, поэтому при определении типа данных с записью для каждого поля записи в область видимости добавляется функция-селектор. Расширение NoFieldSelectors отключает эту возможность, позволяя:
- объявить привязку верхнего уровня с тем же именем, что и у поля, и
- однозначно ссылаться на эту привязку верхнего уровня в выражениях.
Метки полей по-прежнему можно использовать при создании записей, обновлении полей и сопоставлении с образцом.
Например, если задано определение типа данных
data Foo = MkFoo { bar :: Int, baz :: String }
будут доступны следующие элементы:
- конструктор типа
Foo; - конструктор данных
MkFoo; - поля
barиbazдля создания записей, обновления полей и сопоставления с образцом; и - функции-селекторы
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).