Spec-Zone.ru › Haskell 9

6.7.5. Шаблоны «или»

OrPatterns
Since:

9.12.1

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

Шаблоны «или» активируются расширением языка OrPatterns.

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

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

data Sweet = Cupcake | Liquorice | Cookie | Raisins

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

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

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

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

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

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

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

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

Шаблон «или» выглядит так:

(pat_1; ...; pat_n)

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

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

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

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

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`

Это связано с тем, что пока не предложена более общая статическая семантика для таких шаблонов «или».

Итак, что могут делать шаблоны «или»?

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

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

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

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

(Точная синтаксическая конструкция и семантика шаблонов «или» находятся здесь.)

© 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.12.1/docs/users_guide/exts/or_patterns.html

Spec-Zone.ru

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