precedence bug with derived instances
Dean Herington
heringto@cs.unc.edu
Fri, 18 Oct 2002 11:50:29 -0400
Simon Peyton-Jones wrote:
> | In GHC 5.04.1, derived instances of Show mishandle precedence:
> |
> | Prelude> putStrLn (showsPrec 10 (Just 0) "")
> | Just 0
> |
> | The result should be: (Just 0)
>
> I think it's a bug in the Report, not in GHC, actually. The Report says
> (Section D.4)
>
> "The function 'showsPrec d x r' accepts a precedence level 'd'
> (a number from 0 to 10), a value 'x', and a string 'r'.
> ....
> "The representation will be enclosed in parentheses if the precedence
> of the top-level constructor operator in 'x' is less than 'd'. Thus,
> if 'd' is 0 then the result is never surrounded in parentheses; if
> 'd' is 10 it is always surrounded in parentheses, unless it is an
> atomic expression."
>
> But in fact, the precedence of function application is 10, as the
> syntax makes clear. Indeed, the example code at the end of Appendix D
> shows a call to showsPrec with an argument of 11 (it's written
> "app_prec + 1"), for precisely this reason.
>
> So, I think that I have to make these changes to the Report:
>
> (A) The last sentence should say "..; if 'd' is 11 it is always
> surrounded in parentheses, unless it is an atomic expression (recall,
> function application has precedence 10)".
>
> (B) The earlier parenthesis should say "(a number from 0 to 11)".
>
> Does anyone disagree?
I agree. I note that GHC recently (5.04.1?) changed to match the changes
you propose above, and Hugs (as of Dec. 2001 version) still matches the
current report.
I reread Appendix D in the revised report
(<http://research.microsoft.com/Users/simonpj/haskell98-revised/haskell98-report-html/derived.html>)
and have some additional comments.
(1) In the first section, in:
instance (cx, cx') => Ci (T u1 ... uk) where { d }
the use of "(cs, cs')" is a bit loose (that is, suggestive rather than
precise syntax). One can't (according to the report, though GHC seems to
allow it) have nested parentheses in a context, which would occur if cx
included parentheses.
(2) In section D.1, in:
For example, False < _|_ is _|_, even though False is the first
constructor of the Bool type.
change the operator from "<" to "<=". There is no reason to expect (False <
_|_) to be True.
(3) Section D.4 gives the expected rule:
head (readsPrec d (showsPrec d x "")) == (x,"")
Why should this not be:
readsPrec d (showsPrec d x "") == [(x,"")]
(4) I don't understand this paragraph in section D.4:
readsPrec will parse any valid representation of the standard types
apart from lists, for which only the bracketed form [...] is accepted. See
Appendix A for full details.
The statement seems to say that ((readsPrec 5 (show
"abc"))::[([Char],String)]) is invalid, but that can't be what it means to
say.
(5) The next paragraph of section D.4 says:
Spaces and parentheses are only added where needed, ignoring
associativity.
The phrase "only where needed" suggests that (show (1 :$ 2 :$ NT)) should
produce the string "1:$(2:$NT)" (no spaces) rather than the string "1 :$ (2
:$ NT)", as claimed later in the section (and borne out by GHC). It needs
to be stated that an infix operator is preceded and followed by a space.
(6) In the bullet that begins "The derived Read instance allows", change
"parenthese" to "parentheses".
-- Dean