
Now, I say 'trivial' since the actual fix is incredibly minor - a change of compose (.) to apply ($). What was less trivial was the (additional) hair loss arriving at the fix
Tell me about it - when experimentally making a larger project work with GHC 8, I spent a lot of time trying to understand the problem and was rather disappointed that the climax of this effort was to replace `a = f . g` by `a x = f (g x)` in two places. The 8.0 migration guide https://ghc.haskell.org/trac/ghc/wiki/Migration/8.0 already has a section about "Impredicative types brokenness" - I would have appreciated if it contained the simple sentence "In many cases, this can be fixed by rewriting `a = f . g` to `a x = f (g x)`." Maybe somebody can add it.
* I assume previously GHC did not fully check type aliases that were impredictive prior to GHC 8?
Yes, https://ghc.haskell.org/trac/ghc/wiki/Migration/8.0#Requirementforimpredicat...: "In previous versions of GHC, it was possible to hide an impredicative type behind a type synonym, because GHC did not always expand type synonyms when checking for impredicativity."
* What does this imply for a type alias such as for the alias RunInBase used in monad-control that contains RankNTypes: http://hackage.haskell.org/package/monad-control-1.0.1.0/docs/Control-Monad-... - Is such an alias not safe in some sense? (Was it never safe?)
I'll let others answer this one.
* How does the use of ($) vs (.) fix this particular issue? (I'd naively assume the usage here would be equivalent.) I recall reading about ($)'s magical type alias somewhere - is this related?
This page (I'm not sure if you already knew it before asking the question) https://ghc.haskell.org/trac/ghc/wiki/ImpredicativePolymorphism describes the difference between `test1 x = foo (bar x)` and `test2 = foo . bar`; it also has a "Special case for ($)" section which I believe is the answer to your question. The summary is: " But Haskell programmers use ($) so much, to avoid writing parentheses, that GHC's type inference has an ad-hoc special case for ($) that allows it to do type inference for (e1 $ e2), even when impredicative polymorphism is needed. " Niklas