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