
#11243: Flag to not expand type families -------------------------------------+------------------------------------- Reporter: crockeea | Owner: Type: feature request | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 7.10.2 Resolution: | 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 simonpj): The underlying issue is this: * Suppose `F` is a type function with an instance for `F [Int]`. If we have constraints 1. `(C (F [Int]))`, where `C` is a class 2. `F [Int] ~ Maybe Bool` 3. `G (F [Int]) ~ Maybe Bool` then we want to apply the instance in case that unlocks the class constraint or equality. * That expansion may be fruitless. For (1), perhaps `F [Int]` expands to `Bool`, `C` has no `Bool` instance. Then would you prefer to see "can't solve `C (F [Int])`" or "can't solve `C Bool`? Perhaps the latter. * In (3) we might expand `F [Int]` vigorously to get a big type, and ''still'' not be able to simplify the call to `G`. In the case of type synonyms we can have the best of both worlds. Say we have {{{ type T a = S a a }}} Then the type `T [Int]` is represented (essentially) as a pair of its expanded and un-expanded form; so we can freely choose to use either at any time. But it's not so easy for type functions becuase the expanded and un- expanded forms are not interchangeable; there's a coercion involved. I think we could still be a bit less aggressive about expansion. We even implemted this once. But we disabled it for ill-understood performance reasons. Here is the Note from `TcFlatten`: {{{ Note [Lazy flattening] ~~~~~~~~~~~~~~~~~~~~~~ The idea of FM_Avoid mode is to flatten less aggressively. If we have a ~ [F Int] there seems to be no great merit in lifting out (F Int). But if it was a ~ [G a Int] then we *do* want to lift it out, in case (G a Int) reduces to Bool, say, which gets rid of the occurs-check problem. (For the flat_top Bool, see comments above and at call sites.) HOWEVER, the lazy flattening actually seems to make type inference go *slower*, not faster. perf/compiler/T3064 is a case in point; it gets *dramatically* worse with FM_Avoid. I think it may be because floating the types out means we normalise them, and that often makes them smaller and perhaps allows more re-use of previously solved goals. But to be honest I'm not absolutely certain, so I am leaving FM_Avoid in the code base. What I'm removing is the unique place where it is *used*, namely in TcCanonical.canEqTyVar. See also Note [Conservative unification check] in TcUnify, which gives other examples where lazy flattening caused problems. Bottom line: FM_Avoid is unused for now (Nov 14). Note: T5321Fun got faster when I disabled FM_Avoid T5837 did too, but it's pathalogical anyway }}} In short, here's a project for someone! -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/11243#comment:12 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler