-
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).