-
ViewPatterns -
- Начиная с:
-
6.10.1
Разрешает использовать синтаксис шаблонов-представлений.
Шаблоны-представления включаются с помощью языкового расширения ViewPatterns. Дополнительную информацию и примеры использования шаблонов-представлений можно найти на странице Wiki.
Шаблоны-представления чем-то напоминают защитные выражения в шаблонах, которые можно вкладывать в другие шаблоны. Это удобный способ сопоставления с образцом значений абстрактных типов. Например, при реализации языка программирования синтаксис типов языка можно представить следующим образом:
type Typ
data TypView = Unit
| Arrow Typ Typ
view :: Typ -> TypView
-- additional operations for constructing Typ's ...
Представление Typ скрыто, что позволяет реализациям использовать сложное представление (например, хеш-консинг для управления совместным использованием). Без шаблонов-представлений использовать эту сигнатуру немного неудобно:
size :: Typ -> Integer size t = case view t of Unit -> 1 Arrow t1 t2 -> size t1 + size t2
Вместо определения функции с помощью уравнений приходится использовать перебор вариантов. А если сопоставление с t вложено глубоко в другой шаблон, ситуация становится ещё хуже.
Шаблоны-представления позволяют вызывать функцию-представление внутри шаблона и сопоставлять с образцом результат её вызова:
size (view -> Unit) = 1 size (view -> Arrow t1 t2) = size t1 + size t2
Иными словами, мы добавляем новую форму шаблона, записываемую как ⟨expression⟩ -> ⟨pattern⟩, которая означает: «применить выражение к тому, с чем мы пытаемся сопоставить значение, а затем сопоставить результат этого применения с шаблоном». Выражением может быть любое выражение Haskell функционального типа; шаблоны-представления можно использовать везде, где применяются шаблоны.
Семантика шаблона ( ⟨exp⟩ -> ⟨pat⟩ ) такова:
-
Область видимости: переменные, связываемые шаблоном-представлением, — это переменные, связываемые ⟨pat⟩.
Любые переменные в ⟨exp⟩ являются связанными вхождениями, но переменные, связанные «слева» в шаблоне, находятся в области видимости. Эта особенность позволяет, например, использовать один аргумент функции в представлении другого аргумента. Например, функцию
clunkyиз раздела Защитные выражения в шаблонах можно записать с помощью шаблонов-представлений следующим образом:clunky env (lookup env -> Just val1) (lookup env -> Just val2) = val1 + val2 ...other equations for clunky...
Точнее, правила области видимости таковы:
-
В одном шаблоне переменные, связанные шаблонами слева от выражения шаблона-представления, находятся в области видимости. Например:
example :: Maybe ((String -> Integer,Integer), String) -> Bool example (Just ((f,_), f -> 4)) = True
Кроме того, в определениях функций переменные, связанные при сопоставлении с более ранними аргументами каррированной функции, можно использовать в выражениях шаблонов-представлений для последующих аргументов:
example :: (String -> Integer) -> String -> Bool example f (f -> 4) = True
Иными словами, область видимости такая же, как если бы каррированные аргументы были объединены в кортеж.
-
Взаимно рекурсивные связывания, такие как
let,whereили связывания на верхнем уровне, не позволяют шаблонам-представлениям в одном объявлении ссылаться на переменные, связанные другими объявлениями. То есть каждое объявление должно быть самодостаточным. Например, следующая программа недопустима:let {(x -> y) = e1 ; (y -> x) = e2 } in x
(Некоторые дополнительные пояснения к этому решению см. в #4061.)
-
- Типизация: если ⟨exp⟩ имеет тип ⟨T1⟩
->⟨T2⟩, а ⟨pat⟩ сопоставляется со значением типа ⟨T2⟩, то весь шаблон-представление сопоставляется со значением типа ⟨T1⟩. -
Сопоставление: к уравнениям из раздела 3.17.3 отчёта Haskell 98 добавляется следующее:
case v of { (e -> p) -> e1 ; _ -> e2 } = case (e v) of { p -> e1 ; _ -> e2 }То есть, чтобы сопоставить переменную ⟨v⟩ с шаблоном
(⟨exp⟩->⟨pat⟩), вычисляется(⟨exp⟩ ⟨v⟩), а затем результат сопоставляется с ⟨pat⟩. -
Эффективность: если одна и та же функция-представление применяется в нескольких ветвях определения функции или выражения case (например, в
sizeвыше), GHC пытается объединить эти применения в одно вложенное выражение case, чтобы функция-представление применялась только один раз. При компиляции шаблонов GHC использует матричный алгоритм, описанный в главе 4 книги «Реализация функциональных языков программирования». Если верхние строки первого столбца матрицы состоят из шаблонов-представлений с «одинаковым» выражением, эти шаблоны преобразуются в одно вложенное выражение case. Например, это применимо к соседним шаблонам-представлениям, расположенным на соответствующих местах в кортеже, как здесь:f ((view -> A, p1), p2) = e1 f ((view -> B, p3), p4) = e2
Текущее понятие «одинаковости» выражений шаблонов-представлений очень ограничено: оно не сводится даже к полному синтаксическому равенству. Однако оно включает переменные, литералы, применения функций и кортежи; например, два экземпляра
view ("hi", "there")будут объединены. Однако текущая реализация не сравнивает выражения с точностью до альфа-эквивалентности, поэтому два экземпляра(x, view x -> y)объединены не будут.