【问题标题】:How to tell whether parentheses are necessary or not?如何判断括号是否必要?
【发布时间】:2019-05-04 05:41:34
【问题描述】:

我在 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

有没有办法衡量需要多少括号以使语义永远不会模棱两可?我很感激任何反馈。

【问题讨论】:

  • 查看showsPrec,其中shows 与给定运算符Precedence 相关。
  • @AJFarmar 你能推荐一些关于如何使用showsPrec 的教程吗?我在上面找到的文档非常少。
  • @AJFarmar 或者提供一个答案:)
  • 这也是品味问题。在我自己的首选约定中,∀ X 的优先级最低,因此∀ X . A & B 表示∀ X . (A & B),而不是(∀ X . A) & B。 (有时会使用其他优先级。)Haskell 还使\ x -> 尽可能向右扩展。您必须选择优先级。
  • @chi 通常我会同意你的观点,但考虑到我使用这个语法的目的,事实证明给连词赋予较低的优先级更方便。我的问题不是关于选择优先级,而是关于如何实际实现show 函数,以便最少地打印括号。

标签: parsing haskell pretty-print


【解决方案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 之类的内容,而是添加括号。

【讨论】:

  • @HTNW 实际上,这只是“风格”的问题。 :)
  • 我知道你是随机选择的,但你能澄清一下整数 5 和 8 在这里的实际作用吗?为什么不是 1 和 2?
  • @LukeCollins 原则上,它们的价值并不重要,只有它们的排序才重要。但是,应该尝试根据标准库已经使用的级别选择正确的顺序。否则,公式将自行正确打印,但如果例如在Just 中,作为我写的最后一个示例显示。在我的实验中,Just x 将级别 11 赋予x,因此触发括号。相反,[x] 将级别 0 赋予 x - 这里不需要括号。可能在 1 到 10 之间选择你的级别应该没问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-12
  • 1970-01-01
  • 2012-05-09
  • 2021-11-30
  • 1970-01-01
  • 2019-08-14
相关资源
最近更新 更多