Подтвердить что ты не робот

Что обычно означает, что когда аксессуар записи Haskell ведет с подчеркиванием?

Пример из библиотеки HaskellNet:

data MailboxInfo = MboxInfo { _mailbox :: MailboxName
                            , _exists :: Integer
                            , _recent :: Integer
                            , _flags :: [Flag]
                            , _permanentFlags :: [Flag]
                            , _isWritable :: Bool
                            , _isFlagWritable :: Bool
                            , _uidNext :: UID
                            , _uidValidity :: UID
                            }
                 deriving (Show, Eq)

Подчеркивает ли подчеркивание в названиях полей что-то, если не компилятору, то, по крайней мере, согласно соглашению Haskell?

4b9b3361

Ответ 1

По аналогии с подчеркиванием, представляющим нерелевантный шаблон, например. fst (x, _) = x, префикс подчеркивания (в полях записи или иначе) используется для указания того, что кто-либо читает код или игнорируется компилятором для определенных видов взаимодействия с пользователем, даже если ему было дано имя по какой-то причине.

Обратите внимание, что это не просто соглашение, но на основе явно выраженного в отчете Haskell:

Подчеркивание, "_", рассматривается как строчная буква и может происходить везде, где может быть строчная буква. Тем не менее, "_" само по себе является зарезервированным идентификатором, который используется в качестве "диких" карт в шаблонах. Компиляторам, которые предлагают предупреждения для неиспользуемых идентификаторов, рекомендуется подавлять такие предупреждения для идентификаторов, начинающихся с подчеркивания. Это позволяет программистам использовать "_foo" для параметра, который, как они ожидают, не используется.

Одним из примеров может быть определение, которое предназначено для использования Template Haskell, которое затем определяет эквивалентные идентификаторы без подчеркивания, как в распространенном примере генерации объективов на основе полей записи (что, я думаю, является тем, что делает ваш пример). В этом случае идентификаторы более вводятся в TH, чем фактическое определение; код, созданный TH, может или не может фактически использовать идентификаторы подчеркивания-префикса.

Кроме вышеописанного, префикс подчеркивания не делает ничего иначе, как обычный строчный идентификатор.

Ответ 3

Это просто хорошая практика программирования.

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

Ответ 4

Недавно я обнаружил что-то, имеющее отношение к вашему вопросу.

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

module Coords (Coords(), -- hide the constructor
               x,y,buildCoords) where

data Coords = Coords { x :: Int, y :: Int }

buildCoords :: Int -> Int -> Coords
buildCoords x y | x < 0 || y < 0 = error "omg"
buildCoords x y = Coords { x = x, y = y }

Тогда, я рассуждал, вне этого модуля, ни один код не мог создать недопустимые Coords.

Я ошибся! x и y являются общедоступными, поэтому просто нужно использовать let c = buildCoords 1 1 in c { x = -1 } для получения недопустимого значения Coords!

Но этот синтаксис возможен только потому, что x и y являются селекторами записи типа. Способ разрешать только допустимые значения:

module Coords (Coords(), -- hide the constructor
               x,y,buildCoords) where

data Coords = Coords { _x :: Int, _y :: Int }
x = _x
y = _y

buildCoords :: Int -> Int -> Coords
buildCoords x y | x < 0 || y < 0 = error "omg"
buildCoords x y = Coords { _x = x, _y = y }

Теперь x и y являются просто регулярными функциями. Синтаксис c { x = -1 } не будет компилироваться, а другие модули не имеют доступа к селектору записи _x.

Проблема была решена с помощью подчеркивания; -)