Haskell中具有运算符优先级和关联性的漂亮打印语法树

jul*_*les 5 haskell pretty-print abstract-syntax-tree

是否有任何常用的方法甚至库来漂亮地打印(和解析)带有(二进制)运算符的语法树,并为其分配了关联性和优先级,以便结果使用尽可能少的括号?


以命题演算的公式为例:

data Formula
    = Atom String
    | Not (Formula)
    | And (Formula) (Formula)
    | Or (Formula) (Formula)
    | Imp (Formula) (Formula) 
Run Code Online (Sandbox Code Playgroud)

假定优先级为Imp< Or< And< Not(所以Not结合最),并且AndOrImp应关联到的权利; 所以例如Imp (And (Imp (Atom "A") (Atom "B")) (Atom "A")) (Atom "B")应该打印像(A -> B) /\ A -> B


当然,这可以通过模式匹配来实现,但这很繁琐而且非常不愉快。我正在从Coq证明助理中寻找与此符号类似的简单内容:

Notation "A /\ B" := (and A B) (at level 80, right associativity).
Run Code Online (Sandbox Code Playgroud)

生成一个解析器和一个漂亮的打印机。

pat*_*pat 5

Show实例Formula可能如下所示:

instance Show Formula where
  showsPrec _ (Atom name) = showString name
  showsPrec p (Not formula) = showParen (p > 3) $
    showString "\\+ " . showsPrec 3 formula
  showsPrec p (And lhs rhs) = showParen (p > 2) $
    showsPrec 3 lhs . showString " /\\ " . showsPrec 2 rhs
  showsPrec p (Or lhs rhs) = showParen (p > 1) $
    showsPrec 2 lhs . showString " \\/ " . showsPrec 1 rhs
  showsPrec p (Imp lhs rhs) = showParen (p > 0) $
    showsPrec 1 lhs . showString " -> " . showsPrec 0 rhs
Run Code Online (Sandbox Code Playgroud)

这将允许 anyFormula成为shown 并带有适当的括号:

main = print $ Imp (And (Imp (Atom "A") (Atom "B")) (Atom "A")) (Atom "B")
Run Code Online (Sandbox Code Playgroud)

打印(printputStrLn . show):

(A -> B) /\ A -> B
Run Code Online (Sandbox Code Playgroud)