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

Общей проблемой, которую я получил в Haskell, является извлечение всех терминов в списке, принадлежащем конкретному конструктору данных, и мне интересно, есть ли какие-то лучшие способы, чем то, как я это делаю в данный момент.

Скажем, вы получили

data Foo = Bar | Goo

список

foos = [Bar, Goo, Bar, Bar, Goo]

и хотите извлечь все Goo из foos. На данный момент я обычно делаю что-то вроде

goos = [Goo | Goo <- foos]

и все хорошо. Проблема в том, когда Goo получил кучу полей, и я вынужден написать что-то вроде

goos = [Goo a b c d e f | Goo a b c d e f <- foos]

который далеко не идеален. Как обычно вы справляетесь с этой проблемой?

Ответ 1

Похоже, есть две части этого вопроса:

  • Есть ли более простой способ сделать сопоставление с образцом
  • Являются ли перечисления здесь здесь?

Во-первых, там есть лучший способ сопоставления полей, которые вам не нужны:

goos = [ x | [email protected](Goo {}) <- foos]

Во-вторых, использование списков - это совершенно кропотливый способ записи таких фильтров. Например, в базовой библиотеке catMaybes определяется как:

catMaybes :: [Maybe a] -> [a]
catMaybes ls = [x | Just x <- ls]

(из базовой библиотеки). Так что идиома в порядке.

Ответ 2

Вы можете использовать

[x | [email protected](Goo _ _ _ _ _ _) <- foos]

Вы также можете определить

isGoo :: Foo -> Bool
isGoo (Goo _ _ _ _ _ _) = True
isGoo _ = False

а затем используйте filter

filter isGoo foos

или

[x | x <- foos, isGoo]