
#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