Ответ 1
Собственно, они принципиально разные! По крайней мере, в Хаскелле, во всяком случае.
Гвардии более простые и гибкие: они по сути являются просто специальным синтаксисом, который переводится в ряд выражений if/then. Вы можете помещать произвольные булевы выражения в охранники, но они не делают ничего, что вы не могли сделать с регулярным if
.
Совпадения шаблонов выполняют несколько дополнительных действий: они являются единственным способом деконструировать данные, и они связывают идентификаторы в пределах своей области. В том же смысле, что охранники эквивалентны выражениям if
, соответствие шаблонов эквивалентно выражениям case
. Объявления (либо на верхнем уровне, либо в виде выражения let
) также являются формой соответствия шаблона, при этом "обычные" определения совпадают с тривиальным шаблоном, одним идентификатором.
Сравнение шаблонов также, как правило, является основным способом, который на самом деле происходит в Haskell - попытка деконструировать данные в шаблоне является одной из немногих вещей, которая заставляет оценить.
Кстати, вы можете фактически сопоставлять шаблоны в объявлениях верхнего уровня:
square = (^2)
(one:four:nine:_) = map square [1..]
Это иногда полезно для группы связанных определений.
GHC также предоставляет расширение ViewPatterns, которое сочетает в себе оба; вы можете использовать произвольные функции в контексте привязки, а затем сопоставить результат по результату. Конечно, это все еще просто синтаксический сахар для обычных вещей.
Что касается ежедневной проблемы, из-за которой можно использовать где-то несколько грубых руководств:
-
Определенно используйте сопоставление шаблонов для всего, что может быть сопряжено непосредственно с одним или двумя конструкторами в глубину, где вам действительно не нужны сложные данные в целом, но заботитесь о большей части структуры. Синтаксис
@
позволяет привязывать общую структуру к переменной, а также сопоставление шаблонов на ней, но слишком много из того, что в одном шаблоне может быть уродливым и нечитаемым быстро. -
Определенно используйте защитные приспособления, когда вам нужно сделать выбор на основе некоторого свойства, которое не соответствует аккуратно шаблону, например. сравнивая два значения
Int
, чтобы увидеть, что больше. -
Если вам нужна только несколько частей данных из глубины большой структуры, особенно если вам также необходимо использовать структуру в целом, функции защиты и доступа, как правило, более читабельны, чем какой-то чудовищный шаблон, полный
@
и_
. -
Если вам нужно сделать то же самое для значений, представленных разными шаблонами, но с удобным предикатом для их классификации, использование одного общего шаблона с защитой обычно более читаемо. Обратите внимание, что если набор охранников не является исчерпывающим, все, что не срабатывает, все защитники упадут до следующего шаблона (если есть). Таким образом, вы можете комбинировать общий шаблон с каким-то фильтром, чтобы улавливать исключительные случаи, а затем сопоставлять шаблоны во всем остальном, чтобы получить информацию, о которой вы заботитесь.
-
Определенно не используйте защитные устройства для вещей, которые могут быть тривиально проверены с помощью шаблона. Проверка пустых списков - это классический пример, используйте для этого шаблон соответствия.
-
В общем, если вы сомневаетесь, просто придерживайтесь шаблона по умолчанию, он обычно приятнее. Если шаблон начинает становиться действительно уродливым или запутанным, остановитесь, чтобы рассмотреть, как еще вы могли его написать. Помимо использования защитных устройств, другие варианты включают в себя извлечение подвыражений в виде отдельных функций или размещение выражений
case
внутри тела функции, чтобы подтолкнуть некоторые из шаблонов к ним и из основного определения.