Как я могу уменьшить синтаксический беспорядок при пометке полиморфного дерева в Haskell?
Итак, мне нужен тип, представляющий деревья, содержащие набор node -типов. Мне также нравятся типы, которые представляют собой аналогичное дерево, определенное над перекрывающимися наборами. Это еще одна версия проблемы Typed AST. Скажем, что мой пул node -типов:
data Lit = Lit Int
data Var = Var String
data Hole = Hole Int
Дерево разбора может содержать Lit
или Var
, но не Hole
s. Второе дерево вида, называемое шаблоном, может содержать Lit
s, Var
или Hole
s.
Чтобы все было просто, существует один тип рекурсивного node, называемый Add
.
data Parse = A Lit | B Var
data Template = C Lit | D Var | E Hole
data Tree a = Leaf a
| Add (Tree a) (Tree a)
Итак, теперь я могу объявить данные, и я могу по-прежнему сопоставлять их с шаблонами, единственная проблема - синтаксический беспорядок.
aParse = Add (A Lit 3) (B Var "x")
aTemplate = Add (C Lit 4) (E Hole 3)
fun (Add (A lit) (B var) = ...
Я бы хотел немного сахара, похожего на:
ParseLit = A . Lit
TempLit = C . Lit
Очевидно, что псевдонимы для композиций конструкторов (не типов) не являются законными в Haskell. Но каков самый чистый способ написать это, избегая как можно большего количества котельной плиты?
Ответы
Ответ 1
Здесь может помочь расширение языка PatternSynonyms
. Он позволяет указать псевдонимы для шаблонов:
{-# LANGUAGE PatternSynonyms #-}
pattern ParseLit x = A (Lit x)
someFunc :: Parse -> Int
someFunc p = case p of
ParseLit x -> x
_ -> 0
Существует два варианта синонимов шаблонов: двунаправленный (как в примере) и однонаправленный. Двунаправленные могут также использоваться в качестве конструкторов:
*Main> :t ParseLit
ParseLit :: Int -> Parse
*Main> ParseLit 77