
On July 6, 2012 11:49:23 Tyson Whitehead wrote:
Currently it depends on the depth of this new level of indentation relative to all the groupings started on that line. I think most people would expect it to just apply to the last grouping though. That is
where { f x = do { stmt1 stmt2 } }
mask $ let { x = do { stmt1 stmt2 } }
The rule in this case would be that if the grouping began on a newline that is idented farther then the previous line, the grouping is assocated with the grouping token and when it closes, it closes all those deeper than itself.
I've thought some more about this and it seems to me that there are two ways people might intuitively think about doing grouping via indentation. 1 - the first item is on the same line and subsequent ones are lined up with it do stmt1 stmt2 2 - the first item is on a new line and subsequent ones are lined up with it. do stmt1 stmt2 The current layout engine is targeted at (1). It appears to do (2), but it is not really reliable as things start to go south if the first line happened to open more than one grouping (precisely the problem that make '\' a group token would introduce in codes). For an example, consider let greet name = do putStr "hello " putStrLn name in f "world" It currently translates into let { greet name = do {} } putStr "hello " putStrLn name in f "world" This results in an unituituve "Empty 'do' construct" error message. I propose we detected (2) and make it work too. That is, if the line ends with a grouping construct and the next line is indented relative to that line, then assume we really don't want '{}' and instead always start grouping (even if it isn't indented further than other possible groupings also started). In other words, translate the above into let { greet name = do { putStr "hello"; putStrLn name }} in f "world" This would then correctly handle the problamatic case raised in wiki where mask $ \restore -> do stmt1 stmt2 is in translated into mask $ \ { restore -> do {} } stmt1 stmt2 under the current rules if '\' is made a grouping token. The very limited scope of this (i.e., it would only apply to lines that end with a grouping construct where the next line is indented further than that line) should also address Simon's concerns regarding things like f x y = x + y where -- I just left this where here by accident g x = ... and instance Exception Foo where instance Exception Bar Cheers! -Tyson PS: To be fully precise, the modified layout decoder in 9.3 would be L (<n>:ts) i (m:ms) = ; : (L ts n (m:ms)) if m = n = } : (L (<n>:ts) n ms) if n < m L (<n>:ts) i ms = L ts n ms L ({n}:<n>:ts) i ms = { : (L ts n (n:ms)) if n > i (new rule) L ({n}:ts) i (m:ms) = { : (L ts i (n:m:ms)) if n > m (Note 1) L ({n}:ts) i [] = { : (L ts i [n]) if n > 0 (Note 1) L ({n}:ts) i ms = { : } : (L (<n>:ts) i ms) (Note 2) L (}:ts) i (0:ms) = } : (L ts i ms) (Note 3) L (}:ts) i ms = parse-error (Note 3) L ({:ts) i ms = { : (L ts i (0:ms)) (Note 4) L (t:ts) i (m:ms) = } : (L (t:ts) i ms) if m /= 0 and parse-error(t) (Note 5) L (t:ts) i ms = t : (L ts i ms) L [] i [] = [] L [] i (m:ms) = } : L [] i ms if m /= 0 (Note 6) http://www.haskell.org/onlinereport/syntax-iso.html As before, the function 'L' maps a layout-sensitive augmented token stream to a non-layout-sensitive token stream, where the augmented token stream includes '<n>' and '{n}' to, respectively, give the indentation level of the first token on a new line and that following a grouping token not followed by '{'. This time though, we allow the '{n}' '<n>' sequence (before it was supressed to just '{n}'). We also add a new state variable 'i' to track the indentation of the current line. The new rule now opens a grouping over a newline so long as the indentation is greater than the current line. Upon a less indented line, it will then close all currently open groups with an indentation less than the new line.