[GHC] #12235: Wrong compilation of bang patterns

GHC ghc-devs at haskell.org
Mon Jun 27 13:25:00 UTC 2016


#12235: Wrong compilation of bang patterns
-------------------------------------+-------------------------------------
        Reporter:  osa1              |                Owner:
            Type:  bug               |               Status:  closed
        Priority:  normal            |            Milestone:
       Component:  Compiler          |              Version:  8.1
      Resolution:  invalid           |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
                                     |  Unknown/Multiple
 Type of failure:  None/Unknown      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by osa1):

 OK, I figured this out.

 Haskell2010 section 4.4.3.1 says this about translating equation-style
 definitions to case expressions:

     A function binding binds a variable to a function value. The general
 form
     of a function binding for variable `x` is:

         x p11 … p1k match1
         …
         x pn1 … pnk matchn

     where each `pij` is a pattern, and where each `matchi` is of the
 general
     form:

     <snip>

     Translation: The general binding form for functions is semantically
     equivalent to the equation (i.e. simple pattern binding):
         x = \ x1 … xk ->
                 case (x1, …, xk) of
                     (p11, …, p1k) match1
                     …
                     (pn1, …, pnk) matchn

     where the xi are new identifiers.

 GHC user manual 9.28.1 says `-XBangPatterns` adds a new production to the
 pattern syntax:

     pat ::= !pat

 So now let's say I have this:

 {{{
 fn5 :: Int -> [T] -> Int
 fn5 i  []       = i
 fn5 i  (A : ts) = fn5 (i + 1) ts
 fn5 !i (B : ts) = fn5 (i + 2) ts
 fn5 i  (C : ts) = fn5 0 ts
 }}}

 According to the report, this should become:

 {{{
 fn5 = \fresh_1 fresh_2 ->
         case (fresh_1, fresh_2) of
           (i,  [])       -> i
           (i,  (A : ts)) -> fn5 (i + 1) ts
           (!i, (B : ts)  -> fn5 (i + 2) ts
           (i,  (C : ts)  -> fn5 0 ts
 }}}

 The semantics is explained I think in this sentence (from the user
 manual):

     Matching an expression e against a pattern !p is done by first
 evaluating e
     (to WHNF) and then matching the result against p.

 in Haskell2010 "3.13 Case Expressions"

     A case expression is evaluated by pattern matching the expression e
 against
     the individual alternatives. The alternatives are tried sequentially,
 from
     top to bottom. ...

 So if we start matching these `i`s from top to bottom, for the third case
 we'd
 need to evaluate `i`. So when it finally came to matching `(i, (C : ts))`
 we've
 already evaluated `i` because we've tried the third pattern.

 Indeed, if I change the definition to

 {{{
 fn5 :: Int -> [T] -> Int
 fn5 i  []       = i
 fn5 i  (A : ts) = fn5 (i + 1) ts
 fn5 i  (C : ts) = fn5 0 ts
 fn5 !i (B : ts) = fn5 (i + 2) ts
 }}}

 It works as expected.

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


More information about the ghc-tickets mailing list