[GHC] #15646: ghci takes super long time to find the type of large fractional number

GHC ghc-devs at haskell.org
Sun Sep 23 12:04:24 UTC 2018


#15646: ghci takes super long time to find the type of large fractional number
-------------------------------------+-------------------------------------
        Reporter:  Johannkokos       |                Owner:
                                     |  JulianLeviston
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:  8.6.1
       Component:  GHCi              |              Version:  8.4.3
      Resolution:                    |             Keywords:  newcomer
Operating System:  Unknown/Multiple  |         Architecture:
 Type of failure:  Compile-time      |  Unknown/Multiple
  performance bug                    |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by simonpj):

 Some thoughts

 * I don't think we should rely on laziness in the compiler. It'll come
 back to bite us.

 * It's not unreasonable that programs with silly literals will blow up at
 runtime, if it is evaluated, because of the `fromRational r` semantics.
 But it should not blow up at compile time.

 * The underlying problem is that, in the compiler, we represent the
 literal as a `Rational`.  In `BasicTypes` we have:
 {{{
 data FractionalLit
   = FL { fl_text :: SourceText     -- How the value was written in the
 source
        , fl_neg :: Bool            -- See Note [Negative zero]
        , fl_value :: Rational      -- Numeric value of the literal
        }
 }}}
   This `FractionalLit` is used in `HsLit` and `HsOverLit`.  And it is
 finally desugar in `Match.dsLit`:
 {{{
 dsLit :: HsLit GhcRn -> DsM CoreExpr
 dsLit l = ...
     HsRat _ (FL _ _ val) ty -> do
       num   <- mkIntegerExpr (numerator val)
       denom <- mkIntegerExpr (denominator val)
       return (mkCoreConApps ratio_data_con [Type integer_ty, num, denom])
 }}}
   That is we finally generate Core for `(n % d)`.

 * But ''why'' do we produce a compile-time `Rational` for the literal??
 For integral values it makes sense to do so, so that we can do constant
 folding (turning `1 + 2` into `3` at compile time).  But by the time we
 get to Core, we've turned it into `n % d` and I don't think we then do any
 useful compile time work.

 So my solution is this:
 1. Drop the `fl_value` field in `FractionalLit`
 2. Change `dsLit` on `FractionalLit` to desugar to `readRational <str>`,
 where`<str>` is the string the user wrote, recorded in the `fl_text`
 field.  That is, defer the construction of the `Rational` to runtime.

 I think that'd be simple to do.

 If we were going to parse a string at runtime, we'd want to be sure that
 parsing would succeed, but I think the lexer has ensured that it's
 parseble.  I suppose another alternative would be to have
 {{{
 data FractionalLit
   = FL { fl_text :: SourceText     -- How the value was written in the
 source
        , fl_neg :: Bool            -- See Note [Negative zero]
        , fl_before, fl_after, fl_exp :: Integer
                                    -- Denotes <before>.<after>E<exp>
        }
 }}}
 THat is, parse the pieces of the string, and record them in the literal.
 Then desugar to `makeRational before after exp` which again defers to
 runtime the building of the `Rational` itself.

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


More information about the ghc-tickets mailing list