<div dir="auto">Hello,</div><div dir="auto"><br></div><div dir="auto">I found that the layout interpretation algorithm in Section 10.3 of Report 2010</div><div dir="auto">produces parse-error when applied to the following code snippet:</div><div dir="auto"><br></div><div dir="auto">[Snippet 1 : The code that fails to be parsed by Report]</div><div dir="auto">main = print t where { t = s where s = 1 :: Int }</div><div dir="auto">[/Snippet 1]</div><div dir="auto"><br></div><div dir="auto">GHC 8.4.4 and GHC 8.6.4 accept this code, which is a good behavior in my opinion.</div><div dir="auto">If we regard the behavior of those current GHCs as correct,</div><div dir="auto">this "bug" in the Report lies in the following lines in the definition of the function L:</div><div dir="auto"><br></div><div dir="auto">[Snippet 2 : A part of the layout interpretation algorithm in the Report]</div><div dir="auto">L (} : ts) (0 : ms) = } : L ts ms (Note 3)</div><div dir="auto">L (} : ts) ms = parse-error (Note 3)</div><div dir="auto">[/Snippet 2]</div><div dir="auto"><br></div><div dir="auto">I suggest this be modified to what follows:</div><div dir="auto"><br></div><div dir="auto">[Snippet 3 : A Suggested modification to Snippet 2]</div><div dir="auto">L (} : ts) (m : ms)</div><div dir="auto">  | m == 0 = } : L ts ms</div><div dir="auto">  | m > 0 = } : L (} : ts) ms</div><div dir="auto">L (} : ts) [] = parse-error</div><div dir="auto">[/Snippet 3]</div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto">Let me explain in detail. </div><div dir="auto">First of all, how is Snippet 1 refused by the Report 2010 algorithm?</div><div dir="auto">Let us emulate it by hand. Firstly pre-process Snippet 1:</div><div dir="auto"><br></div><div dir="auto">[Snippet 4 : Pre-processed Snippet 1]</div><div dir="auto">{1} main = print t where { t = s where {36} s = 1 :: Int }</div><div dir="auto">[/Snippet 4]</div><div dir="auto"><br></div><div dir="auto">I assumed that Snippet 1 is the only line in a file.</div><div dir="auto">We may compute:</div><div dir="auto"><br></div><div dir="auto">[Computation 5 : Apply L to Snippet 4]</div><div dir="auto">L <Snippet 4> []</div><div dir="auto"> = "{ main = print t where { t = s where { s = 1 :: Int"</div><div dir="auto">       ++ L "}" [36,0,1]</div><div dir="auto">[/Computation 5]</div><div dir="auto"><br></div><div dir="auto">Wait here. What does L do next?</div><div dir="auto">Looking from top to bottom, we hit the second line in Snippet 2,</div><div dir="auto">which leads us to parse-error.</div><div dir="auto">Now you might expect that the line</div><div dir="auto"><br></div><div dir="auto">[Snippet 6 : Another part of the Report algorithm]</div><div dir="auto">L (t : ts) (m : ms) = } : (L (t : ts) ms)   if m /= 0 and parse-error(t) (Note 5)</div><div dir="auto">[/Snippet 6]</div><div dir="auto"><br></div><div dir="auto">would help, but unfortunately it doesn't work.</div><div dir="auto">Even if we put aside the fact that Snippet 6 is lower in the text than Snippet 2</div><div dir="auto">and has lower priority of execution according to the usual Haskell matching rule,</div><div dir="auto">this line in L won't be triggered by this parse error at all,</div><div dir="auto">since *parse-error('}') is false!*</div><div dir="auto">Let us go back to the definition of parse-error(t).</div><div dir="auto"><br></div><div dir="auto">[Quotation 7 : Note 5 in the Report algorithm]</div><div dir="auto">The side condition parse-error(t) is to be interpreted as follows: </div><div dir="auto">if the tokens generated so far by L together with the next token t</div><div dir="auto">represent an invalid prefix of the Haskell grammar,</div><div dir="auto">and the tokens generated so far by L followed by the token "}"</div><div dir="auto">represent a valid prefix of the Haskell grammar, then parse-error(t) is true.<br></div><div dir="auto">[/Quotation 7]</div><div dir="auto"><br></div><div dir="auto">Now, this is the point.</div><div dir="auto">In this case, "the tokens generated so far by L together with the next token t" is:<br></div><div dir="auto"><br></div><div dir="auto">[Snippet 8]</div><div dir="auto">{ main = print t where { t = s where { s = 1 :: Int }</div><div dir="auto">[/Snippet 8]</div><div dir="auto"><br></div><div dir="auto">This is a *valid prefix of the Haskell grammar*, and hence parse-error('}') is false.</div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto">Therefore, any Haskell2010-compliant compiler should reject Snippet 1,</div><div dir="auto">and this doesn't seem to be any sensible choice of specification.</div><div dir="auto">Speaking generally, I guess the Report 2010's authors wanted</div><div dir="auto">the case where a inner implicit brace and a outer explicit brace is closed at the same time</div><div dir="auto">to be processed by the rule in Snippet 6,</div><div dir="auto">but it doesn't work since Snippet 2 is before Snippet 6 in the definition of L </div><div dir="auto">and parse-error(t) is always false if t = '}'.</div><div dir="auto"><br></div><div dir="auto">The fix of this problem is easy: replace Snippet 2 with Snippet 3.</div><div dir="auto">The added case of m > 0 is doing almost the same thing as Snippet 6, but parse-error(t) is removed.</div><div dir="auto">If we distinguish implicit close-braces and explicit close-braces,</div><div dir="auto">the condition m > 0 fully does the job of parse-error('}'),</div><div dir="auto">so I expect there will be no problem with this modification.</div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto">I apologize you if this long text has exhausted your eyes.</div><div dir="auto">I hope this suggestion would help.</div><div dir="auto"><br></div><div dir="auto">Sincerely yours,</div><div dir="auto">Genki SATO</div>