<html><head><meta http-equiv="Content-Type" content="text/html; charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On Sep 2, 2020, at 10:18 PM, Anthony Clayden <<a href="mailto:anthony_clayden@clear.net.nz" class="">anthony_clayden@clear.net.nz</a>> wrote:</div><div class=""><div dir="ltr" class=""><pre style="white-space: pre-wrap;" class=""><br class=""></pre><pre style="white-space: pre-wrap;" class="">The compiler expands the synonym to mkPoint :: a -> a -> Num a => (a, a).</pre><pre style="white-space: pre-wrap;" class="">Note no parens around the expansion, unlike my O.P. That expansion is not valid H98, but it is valid in GHC with RankNTypes. The docos say it's a Rank-1 type. GHC infers</pre><pre style="white-space: pre-wrap;" class=""><br class=""></pre><pre style="white-space: pre-wrap;" class="">    mkPoint :: Num a => a -> a -> (a, a)</pre><pre style="white-space: pre-wrap;" class=""><br class=""></pre><pre style="white-space: pre-wrap;" class="">And that's why I call it "floating out". </pre></div></div></blockquote><div>Yes, but what about</div><div><br class=""></div><div>> pointX :: Point a -> a</div><div>> pointX (x, _) = x</div><div><br class=""></div><div>? We don't want that type to expand to (Num a => (a, a)) -> a.</div><div><br class=""></div><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><pre style="white-space: pre-wrap;" class=""> The client writes</pre><pre style="white-space: pre-wrap;" class="">
    scale :: a -> Point a -> Point a</pre><pre style="white-space: pre-wrap;" class="">    -- expand the synonyms; then float out and squish duplicates</pre><pre style="white-space: pre-wrap;" class="">    -- ===> scale :: a -> Num a => (a, a) -> Num a => (a, a)  -- no parens added</pre><pre style="white-space: pre-wrap;" class="">    -- ===> scale :: Num a => a -> (a, a) -> (a, a)</pre><pre style="white-space: pre-wrap;" class="">The 'no parens' step (different to my O.P.) is valid GHC with RankNTypes; the last step is as GHC infers today, with Num a floated out. (Or if you don't like that phrase: "canonicalises", "simplifies"?)</pre></div></div></blockquote><div><br class=""></div><div>Ah. Now I see a bit more of what you're getting at. But I really don't know what it means to expand without adding parens. Expanding a type synonym is an operation on an abstract syntax tree (AST). We often write ASTs by just writing out concrete syntax, and this sometimes requires adding parens. Even so, we're really just operating with ASTs -- and I don't think your "expand without parens" operation is defined on ASTs. For example:</div><div><br class=""></div><div>> data a + b = Inl a | Inr b</div><div>> foo :: Point a + Point b</div><div><br class=""></div><div>I can't imagine we want to expand this to</div><div><br class=""></div><div>> foo :: Num a => (a, a) + Num b => (b, b)</div><div><br class=""></div><div>which, under usual rules of precedence, becomes</div><div><br class=""></div><div>> foo :: Num a => ((a, a) + Num b) => (b, b)</div><div><br class=""></div><div>Note how the + binds tighter than the =>.</div></div><br class=""><div class="">Richard</div></body></html>