#4430: Better support for resolving infix expressions in template haskell
---------------------------------+------------------------------------------
    Reporter:  reinerp           |        Owner:  igloo       
        Type:  feature request   |       Status:  patch       
    Priority:  normal            |    Milestone:  7.4.1       
   Component:  Template Haskell  |      Version:  6.12.3      
    Keywords:                    |     Testcase:              
   Blockedby:                    |   Difficulty:              
          Os:  Unknown/Multiple  |     Blocking:              
Architecture:  Unknown/Multiple  |      Failure:  None/Unknown
---------------------------------+------------------------------------------

Comment(by reinerp):

 Sorry, I guess I didn't explain my thoughts clearly. I'll give it another
 shot.


 == What is the special case ==

 The special case is not explicit, but it's there. In Convert.cvtl, compare
 the cases for {{{InfixE (Just x) s (Just y)}}} and {{{InfixE Nothing s
 (Just y)}}} (this is around line 488). We produce the following output:

 {{{
 InfixE (Just x) s (Just y)   ---> HsPar (OpApp (HsPar x) s (HsPar y))
 InfixE Nothing  s (Just y)   ---> HsPar (SectionR        s y)
 }}}

 Note that the former puts parentheses around the {{{y}}}, whereas the
 latter doesn't. This means that when the renamer runs, the {{{OpApp}}}s
 coming from {{{y}}} will meet the {{{SectionR}}} in the second case, but
 they won't meet the {{{OpApp}}} in the first case. That is:

 {{{
 InfixE (Just x) s (Just (UInfix y op z))
   ---> HsPar (OpApp
                 (HsPar x)
                 s
                 (HsPar (OpApp y op z)))
   (the OpApps don't meet, so they aren't reassociated)

 InfixE Nothing s (Just (UInfix y op z))
   ---> HsPar (SectionR
                s
                (OpApp y op z))
   (the OpApp meets the SectionR, so the renamer will throw an error if
 @op@ is left-infix)
 }}}

 Of course, the same applies the the {{{SectionL}}} case.

 == Option 1, a summary ==
 For comparison with the next section, here is what Option 1 does:

 {{{
 data Exp =
 ...
   | InfixE (Maybe Exp) Exp (Maybe Exp)
   | UInfixE Exp Exp Exp
 ...
 }}}

 and {{{Convert.cvtl}}} does this:

 {{{
 InfixE (Just x) s (Just y)   ---> HsPar (OpApp    (HsPar x) s (HsPar y))
 InfixE Nothing  s (Just y)   ---> HsPar (SectionR           s y        )
 InfixE (Just x) s Nothing    ---> HsPar (SectionL x s                  )
 UInfixE  x      s y          --->       (OpApp    x         s y        )
 }}}

 == What Option 2 would look like ==
 In Option 2, we would have

 {{{
 data Exp =
 ...
  | InfixE (Maybe Exp) Exp (Maybe Exp)
  | UInfixE (Maybe Exp) Exp (Maybe Exp)
 ...
 }}}

 and the relevant parts of {{{Convert.cvtl}}} would be

 {{{
 InfixE (Just x) s (Just y)   ---> HsPar (OpApp    (HsPar x) s (HsPar y))
 InfixE Nothing  s (Just y)   ---> HsPar (SectionR           s (HsPar y))
 InfixE (Just x) s Nothing    ---> HsPar (SectionL (HsPar x) s          )
 UInfixE (Just x) s (Just y)  --->       (OpApp    x         s y        )
 UInfixE Nothing  s (Just y)  --->       (SectionR           s y        )
 UInfixE (Just x) s Nothing   --->       (SectionL x         s          )
 }}}


 == Why option 1 is surprising ==

 Perhaps the comment I wrote was too strongly worded in saying that there
 was a special case. But Option 1 is still surprising.

 Consider:

 {{{
 -- with option 1
 InfixE (Just x) s (Just y)          -- doesn't care if x and y are
 UInfixE's, i.e. no fixity errors, no reassociating
 InfixE Nothing  s (Just y)          -- if y is a UInfixE with a left-infix
 operator, the renamer will throw a fixity error
 InfixE Nothing  s (Just (Parens y)) -- doesn't care if y is a UInfixE
 -- with option 2
 InfixE  (Just x) s (Just y)         -- doesn't care if x and y are
 UInfixE's
 InfixE  Nothing  s (Just y)         -- doesn't care if y is a UInfixE
 UInfixE Nothing  s (Just y)         -- if y is a UInfixE with a left-infix
 operator, the renamer will throw a fixity error
 }}}

 I find option 1 surprising, because I don't expect {{{InfixE}}} to "look
 inside" its argument. And for non-section uses of {{{InfixE}}}, it
 doesn't, but for sections it does! (I can't find a better description for
 what happens in the above examples than "doesn't care" versus "looks
 inside", which is unfortunate, and perhaps a source of the confusion. I
 hope it's clear what I mean.)

 Sorry for dragging things out so long.

 Reiner

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4430#comment:24>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler

_______________________________________________
Glasgow-haskell-bugs mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to