Spec-Zone.ru › Haskell 9

6.7.2. Шаблоны-представления

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) объединены не будут.

© 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/view_patterns.html

Spec-Zone.ru

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