Spec-Zone.ru › Haskell 9

6.7.5. OR-шаблоны

OrPatterns
Начиная с:

9.12.1

Разрешает использовать синтаксис OR-шаблонов.

OR-шаблоны включаются расширением языка OrPatterns.

Они позволяют объединить несколько шаблонов в один.

Предположим, у нас есть некоторый тип-сумма и код, сопоставляющий с ним образец:

data Sweet = Cupcake | Liquorice | Cookie | Raisins

tasty Cupcake = True
tasty Cookie = True
tasty _ = False

Допустим, нам нужно добавить к нашему типу ещё один конструктор, например Cheesecake. Из-за шаблона-универсального случая, который мы использовали при определении tasty, компилятор не предупреждает нас о том, что сопоставление с образцом может потребовать изменений. В результате чизкейк ошибочно характеризуется как невкусный.

Если мы хотим, чтобы компилятор помогал нам в Haskell2010, нам пришлось бы явно перечислить все случаи, из-за чего код стал бы значительно длиннее. Здесь и помогают OR-шаблоны. С помощью OrPatterns мы можем написать:

tasty (Cupcake; Cookie) = True
tasty (Liquorice; Raisins) = False

Если мы добавим к Sweet ещё один конструктор, теперь мы получим предупреждение о неполном сопоставлении с образцом — при условии, что компилируем с флагом -Wincomplete-patterns.

OR-шаблоны особенно полезны при сопоставлении с образцом, когда нужно обработать большое количество конструкторов. Нередко встречаются сопоставления с образцом, охватывающие десятки конструкторов, например, в исходном коде самого GHC (Pat.hs). В таких случаях есть только следующие варианты:

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

6.7.5.1. Спецификация

OR-шаблон выглядит так:

(pat_1; ...; pat_n)

где pat_1, …, pat_n — это шаблоны. OR-шаблоны являются обычными шаблонами и могут использоваться везде, где применимы другие шаблоны.

Результат сопоставления значения x с этим шаблоном:

  • результат сопоставления x с pat_1, если оно не завершилось неудачей
  • в противном случае — результат сопоставления x с (pat_2; ...; pat_n).

Основное ограничение OR-шаблонов на данный момент состоит в том, что они не могут связывать переменные или ограничения. Это запрещает такой код:

value :: Either a a -> a
value (Left x; Right x) = x -- binds a variable

или такой:

data G a where
  G1 :: Num a => G a
  G2 :: Num a => G a

bar :: G a -> a
bar (G1; G2) = 3 -- cannot solve constraint `Num a`

data GADT a where
  IsInt1 :: GADT Int
  IsInt2 :: GADT Int

foo :: a -> GADT a -> a
foo x (IsInt1; IsInt2) = x + 1 -- cannot solve constraint `Num a`

Это ограничение существует лишь потому, что для таких OR-шаблонов пока не предложена более общая статическая семантика.

Итак, что же могут делать OR-шаблоны?

Помимо сокращения размера кода и устранения дублирования, они сочетаются со всеми существующими видами шаблонов, например с шаблонами просмотра и синонимами шаблонов:

f :: (Eq a, Show a) => a -> a -> Bool
f a ((== a) -> True; show -> "yes") = True
f _ _ = False

small (abs -> (0; 1; 2); 3) = True -- -3 is not small
small _ = False

type Coll a = Either [a] (Set a)
pattern None <- (Left []; Right (toList -> []))

empty None = False
empty _ = True

OR-шаблоны не выполняют возврат при использовании охраняемых правых частей: если совпало одно из альтернативных условий OR-шаблона, остальные не проверяются, даже если проверка охраны завершается неудачей. Следующий код выдаёт "no backtracking":

case error "backtracking" of
  (_; True) | False -> error "inaccessible"
  _ -> error "no backtracking"

(Точный синтаксис и семантику OR-шаблонов можно найти здесь.)

© 2002–2007 The University Court of the University of Glasgow. All rights reserved.
Licensed under the Glasgow Haskell Compiler License.
https://downloads.haskell.org/~ghc/9.14.1/docs/users_guide/exts/or_patterns.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API