Ответ 1
Вы можете думать о стражах как о синтаксическом сахаре для утверждения if. Выражение в guard может быть любым допустимым булевым выражением, как и в if-statements. Это означает, что вы можете использовать любые значения и функции в области.
Например, вы можете переписать следующее:
foo x | abc = ...
| def = ...
| otherwise = ...
как
foo x = if abc then ... else if def then ... else ...
Мы также можем записать это немного более подробно с помощью case
, а не if
:
foo x = case abc of
True -> ...
False -> case def of
True -> ...
False -> ...
В конце концов, if
сам по себе является просто синтаксическим сахаром для случая! Написание всего в терминах case
упрощает просмотр того, как разные функции являются просто синтаксическим сахаром для одной и той же вещи.
Второе выражение явно имеет смысл, хотя условия ссылаются на существующие переменные (abc
и def
), а не на параметр функции x
; охранники работают одинаково.
Пример немного сложнее, потому что он использует расширение, называемое "защитой шаблонов" . Это означает, что защита может быть больше, чем просто логическая - она также может попытаться сопоставить шаблон. Если шаблон соответствует, защита будет успешной (например, это то же самое, что защита с True
); в противном случае защитник не может соответствовать (как получение False
).
Мы могли бы переписать его следующим образом:
readPoint s | Just [x, y] <- matchRegex (mkRegex "...") s = ...
| otherwise = ...
а
readPoint s = case matchRegex (mkRegex "...") s of
Just [x, y] -> ...
_ -> ...
Вы можете видеть параллель между этой и версией case
нормальных охранников. Шаблоны защиты просто расширяют десурацию на произвольные шаблоны, а не просто логические.
Опять же, я уверен, вы согласитесь, что имеет смысл разрешить любое выражение в инструкции case
- нет причин ограничивать его использованием аргументов функции. То же самое верно для охранников, потому что они действительно просто синтаксический сахар.