Использование синтаксиса записи с алгебраическими типами данных с несколькими конструкторами

Следующий тип данных является представлением фосфатидной кислоты (PA - подкласс липидов). Используя масс-спектрометрию, можно получить различные уровни структурной детализации (например, от простого знания массы липида до получения полной структурной характеристики).

В настоящее время у меня есть тип данных PA как-

data PA   = ClassLevelPA       IntegerMass
          | CombinedRadylsPA   CombinedRadyls
          | UnknownSnPA        Radyl Radyl
          | KnownSnPA          { paSn1 :: Radyl
                               , paSn2 :: Radyl }
          deriving (Show, Eq, Ord)

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

data PA   = ClassLevelPA       { paIntegerMass :: IntegerMass }
          | CombinedRadylsPA   { paCombinedRadyls :: CombinedRadyls }
          | UnknownSnPA        { paR1 :: Radyl 
                               , paR2 :: Radyl }
          | KnownSnPA          { paSn1 :: Radyl
                               , paSn2 :: Radyl }

data PA   = ClassLevelPA       IntegerMass
          | CombinedRadylsPA   CombinedRadyls
          | UnknownSnPA        Radyl Radyl
          | KnownSnPA          Radyl Radyl

В настоящее время я не использую функции доступа paSn1 и paSn2, но сейчас думаю, что они могут пригодиться позже. Однако более поздняя альтернатива намного чище, а также позволяет избежать необходимости иметь дело с несколькими именами полей для разных записей (до тех пор, пока в GHC не будет добавлено расширение OverloadedRecordFields). Какое из трех представлений предпочтительнее и какова позиция в отношении использования конструкторов с синтаксисом записи с теми, которые этого не делают?


person Michael T    schedule 22.10.2015    source источник
comment
если вам это не нужно прямо сейчас, я бы YAGNI и пошел с последним - вы, вероятно, все равно будете сопоставлять шаблоны все время, и IMO смешанные опасны, поскольку сгенерированные функции доступа будут частичное (например, paR1 (ClassLevelPA im))   -  person Random Dev    schedule 22.10.2015
comment
Спасибо за ваш ответ. Написание частичных функций — это то, чего я определенно хочу избежать, поэтому я избавлюсь от них.   -  person Michael T    schedule 22.10.2015


Ответы (1)


Использование функций доступа для типов данных с более чем одним конструктором не рекомендуется, поскольку эти функции будут частичными. Я думаю, вы могли бы добиться большего успеха, используя призмы и/или обходы из пакета lens. Призмы представляют собой линзовую альтернативу сопоставлению с образцом и применению конструктора. Обходы (что более важно) позволяют вам иметь дело с нулем или более вещами, включая поля, которые могут быть, а могут и не быть. Волшебные функции Template Haskell для обхода, я полагаю, потребуют от вас включения методов доступа (с именами, начинающимися с _), но вам никогда не потребуется использовать их напрямую или экспортировать их.

person dfeuer    schedule 22.10.2015
comment
Обязательно ознакомьтесь с пакетом lens. Это действительно значительно упрощает работу с конструкторами, которые не всегда совпадают (т. е. в случае, когда ваш тип данных имеет только один конструктор). - person drquicksilver; 22.10.2015
comment
Частичные поля обрабатываются обходами, а не призмами. - person András Kovács; 22.10.2015
comment
@ AndrásKovács, так лучше? - person dfeuer; 22.10.2015
comment
@MichaelT Два года и нет принятого ответа? Кстати, я полагаю, вы могли бы использовать обычную старую запись с полями, обернутыми в Maybe. - person SwiftsNamesake; 14.03.2017