Haskell Pattern Matching на пустом наборе

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

foo [] = []
foo x = other_thing

Как я могу написать этот код, чтобы он использовал Sets вместо списков?

Ответ 1

Ну, вы не можете.

Set - это абстрактный тип данных [0] который намеренно скрывает его внутреннее представление, в первую очередь, для сохранения инвариантов структуры данных, которые не могут быть подвергнуты статически принудительной системе типов (в частности, стандартная библиотека Data.Set.Set является двоичным деревом поиска).

Потеря способности сопоставления шаблонов по абстрактному типу данных представляет собой неприятный бит сопутствующего урона, но хорошо. Ваши варианты примерно:

  • Использовать логические предикаты и защитные меры, например. null, как в ответе тринита.
  • Преобразуйте Set в список. В большинстве случаев это глупо, но если вы хотите итерации по набору в любом случае, он работает достаточно хорошо.
  • Включить расширение GHC ViewPatterns, которое обеспечивает синтаксический сахар для использования функций доступа, где обычно идет совпадение с шаблоном.
  • Избегайте делать эти проверки в первую очередь - если у вас есть Set, относитесь к нему как к набору и работайте с ним в целом для сопоставления, фильтрации и т.д. Не всегда возможно, но может привести для более чистого кода с меньшим количеством явных условных выражений/итераций.

Паттерны просмотра позволят вам написать что-то похожее на это:

foo (setView -> EmptySet) = []
foo (setView -> NonEmpty set) = other_thing

... где setView - это функция, которую вы пишете. На самом деле это не очень выгодно, но может быть приятным для более сложных псевдо-шаблонов

Чтобы избежать явных проверок, помимо известных операций с множеством, таких как union и intersection, рассмотрим возможность использования функций filter, partition, map и fold в Data.Set.

[0]: См. этот документ (предупреждение: PDF) для определения термина как я ' используя его.

Ответ 2

import qualified Data.Set as Set

foo set
  | Set.null set = bar
  | otherwise = baz