如何判断是否需要括号?

时间:2018-12-02 22:15:14

标签: parsing haskell pretty-print

我已经在Haskell中编写了一个解析器,该解析器以字符串输入的形式解析公式,并生成由下面的BNF定义的Haskell data类型。

formula ::=  true  
         |  false  
         |  var  
         |  formula & formula  
         |  ∀ var . formula
         |  (formula)

    var ::=  letter { letter | digit }*

现在,我想创建一个Show的实例,以便可以很好地打印由我的类型定义的公式(我不想使用deriving (Show))。我的问题是:如何定义函数,以便可以告诉何时需要括号?我不要太多,也不要太括号。

例如,给定公式∀ X . (X & Y) & (∀ Y . Y) & false,该公式在解析后会产生数据结构

And (And (Forall "X" (And (Var "X") (Var "Y"))) (Forall "Y" (Var "Y"))) False

我们有

   Too little parentheses:    ∀ X . X & Y & ∀ Y . Y & false
   Too much parentheses:      (∀ X . (((X) & (Y)))) & (∀ Y . (Y)) & (false)
   Just right:                ∀ X . (X & Y) & (∀ Y . Y) & false

是否有一种方法可以估计需要多少个括号,以使语义永远不会模棱两可?我感谢任何反馈。

1 个答案:

答案 0 :(得分:1)

未经测试的伪代码:

instance Show Formula where
   showsPrec _p True  = "True"
   showsPrec _p False = "False"
   showsPrec p (And f1 f2) = showParen (p > 5) $
      showsPrec 5 f1 . (" & " ++) . showsPrec 5 f2
   showsPrec p (Forall x f) = showParen (p > 8) $
      ("forall " ++ x ++) . showsPrec 8 f
   ...

(我可能应该使用showString而不是上面的++。我认为应该可以使用。)

以上,整数p表示显示当前公式的上下文的优先级。例如,如果我们在f中显示f & ...,则p的优先级为&

如果需要在优先级更高的上下文中打印符号,则需要添加括号。例如。如果fa | b,我们就不能写a | b & ...,否则它将被解释为a | (b & ...)。我们需要在a | b周围加上括号。这是由showParen (p > ...)完成的。

递归时,我们会将符号的优先级传递给子项。

上面,我随机选择了优先级别。您需要根据自己的喜好调整它们。您还应该检查选择的级别是否与标准库一起播放。例如。打印Just someFormula不应生成类似Just a & b的内容,而应加上括号。