showsPrec和运算符优先级 [英] showsPrec and operator precedences

查看:92
本文介绍了showsPrec和运算符优先级的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我之前曾问过这个问题,但似乎我把这个问题说得太狭窄了.因此,让我们看看我是否可以解释我的实际打算.

I asked about this before, but it seems I phrased the question too narrowly. So let's see if I can explain what I'm actually after.

假设我有某种类型,它支持多个二进制运算符,每个运算符具有不同的优先级和关联性.如何编写一个正确括住子表达式的Show实例?

Suppose I have some type that supports several binary operators, each with varying precedence and associativity. How do I write a Show instance that correctly brackets sub-expressions?

我知道我在这里很稠密,但是每次尝试都会错误地 .您必须遵循一些机械步骤才能正确执行此操作,但是我找不到它.有人可以教我一个例子吗?

I know I'm being dense here, but I get this wrong every single time I try to do it. There must be some mechanical procedure you can follow to make this work out correctly, but I cannot find it. Can somebody walk me through an example?

我知道这最终可以归结为将所有内容包装在showParen中,并使用具有正确魔术数字的showsPrec显示子表达式,并且我可以使其几乎正常工作,但是从来没有在所有情况下都可以正常工作.

I know this ultimately boils down to wrapping everything in showParen, and showing sub-expressions using showsPrec with the right magic number, and I can make it almost work, but it never quite works right in all circumstances.

编辑:考虑以下代码

data Expr =
  Const Int |
  Expr :+: Expr |
  Expr :-: Expr |
  Expr :*: Expr |
  Expr :/: Expr

infixl 6 :+:
infixl 6 :-:
infixl 7 :*:
infixl 7 :/:

instance Show Expr where
  showsPrec p e0 =
    case e0 of
     Const n -> shows n
     x :+: y -> showParen (p > 6) $ (showsPrec 6 x) . (" :+: " ++) . (showsPrec 6 y)
     x :-: y -> showParen (p > 6) $ (showsPrec 6 x) . (" :-: " ++) . (showsPrec 6 y)
     x :*: y -> showParen (p > 7) $ (showsPrec 7 x) . (" :*: " ++) . (showsPrec 7 y)
     x :/: y -> showParen (p > 7) $ (showsPrec 7 x) . (" :/: " ++) . (showsPrec 7 y)

几乎正常工作:

*Main> Const 1 :+: Const 2 :*: Const 3 :+: Const 4
1 :+: 2 :*: 3 :+: 4
*Main> (Const 1 :+: Const 2) :*: (Const 3 :+: Const 4)
(1 :+: 2) :*: (3 :+: 4)

但不完全是

*Main> Const 1 :+: Const 2 :-: Const 3 :-: Const 4
1 :+: 2 :-: 3 :-: 4
*Main> Const 1 :+: Const 2 :-: (Const 3 :-: Const 4)
1 :+: 2 :-: 3 :-: 4

所以看起来 precedence 可以,但是 associativity 却很糟糕.

So it looks like the precedence is OK, but the associativity is borked.

推荐答案

由于showsPrec没有任何方法可以获取上下文的关联性,因此,我认为无法像这样解决此问题,确切地说,最小Haskell括号回.为了确保正确性而又不添加多余的多余括号,请在showParen条件下使用>=:

Since showsPrec hasn't any way to obtain the associativity of the context, I don't think it's possible to fix this as in, get exactly the minimal Haskell parenthesation back. To ensure correctness without adding more redundant parens than necessary, use >= in the showParen condition:

  showsPrec p e0 =
    case e0 of
     Const n -> shows n
     x :+: y -> showParen (p >= 6) $ (showsPrec 6 x) . (" :+: " ++) . (showsPrec 6 y)
     x :-: y -> showParen (p >= 6) $ (showsPrec 6 x) . (" :-: " ++) . (showsPrec 6 y)
     x :*: y -> showParen (p >= 7) $ (showsPrec 7 x) . (" :*: " ++) . (showsPrec 7 y)
     x :/: y -> showParen (p >= 7) $ (showsPrec 7 x) . (" :/: " ++) . (showsPrec 7 y)

然后产生

* Main>常量1:+:常量2:*:常量3:+:常量4
(1:+:2:*:3):+:4
* Main>(Const 1:+:Const 2):*:(Const 3:+:Const 4)
(1:+:2):*:(3:+:4)
* Main>常量1:+:常量2:-:常量3:-:常量4
(((1:+:2):-:3):-:4
* Main>常量1:+:常量2:-:(常量3:-:常量4)
(1:+:2):-:(3:-:4)

*Main> Const 1 :+: Const 2 :*: Const 3 :+: Const 4
(1 :+: 2 :*: 3) :+: 4
*Main> (Const 1 :+: Const 2) :*: (Const 3 :+: Const 4)
(1 :+: 2) :*: (3 :+: 4)
*Main> Const 1 :+: Const 2 :-: Const 3 :-: Const 4
((1 :+: 2) :-: 3) :-: 4
*Main> Const 1 :+: Const 2 :-: (Const 3 :-: Const 4)
(1 :+: 2) :-: (3 :-: 4)

看起来不尽如人意,但还不如showParen (p > n)版本那么糟糕,当然也没有错.基本上,如果我们只有infix,没有infixlinfixr,这将给出最小的括号.

Which doesn't look quite as nice as it could, but not too bad and certainly not wrong like the showParen (p > n) version. Basically, this gives what would be the minimal parenthesization if we had only infix, no infixl or infixr.

如果只希望显示确实需要的paren,则需要传播更多信息,而不仅仅是Int来确保上下文固定.我在其中实现了我对HaTeX的符号数学扩展构想;本质上,它只是在运行时镜像Haskell的infixl等注释.例如,

If you want only those parens to appear which are really necessary, you'll need to propagate more information than just an Int for context fixity. I implemented that kind of thing in my symbolic-math extension idea for HaTeX; essentially it just mirrors Haskell's infixl etc. annotations at runtime. For example,

     exaDisp $ 5 - (4 - 3) + 2 + 1

然后

呈现为

这篇关于showsPrec和运算符优先级的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆