<div dir="ltr"><div dir="auto">Currently, we have something like<div dir="auto"><br></div><div dir="auto">    ($) :: forall r1 r2 (a :: TYPE r1) (b :: TYPE r2).</div><div dir="auto">      (a -> b) -> a -> b</div><div dir="auto">    f $ x = f x</div><div dir="auto"><br></div><div dir="auto">And that's only part of the story: GHC has a hack in the type checker to give ($) an impredicative type when fully applied. This allows it to be used when its function argument requires a polymorphic argument.</div><div dir="auto"><br></div><div dir="auto">This whole complicated situation could be resolved in a very simple manner: change the type and definition thus.</div><div dir="auto"><br></div><div dir="auto">    ($) :: a -> a</div><div dir="auto">    ($) f = f</div><div dir="auto"><br></div><div dir="auto">All the type complications go away altogether, and ($) becomes plain Haskell 98.<br><br>There are only three potential downsides I can think of:</div><div dir="auto"><br></div><div dir="auto">1. The optimizer will see `($) x` as fully applied, which could change its behavior in some cases. There might be circumstances where that is bad. I doubt there will be many.</div><div dir="auto"><br></div><div dir="auto">2. The new type signature may obscure the purpose of the operator to beginners. But based on my experience on StackOverflow, it seems beginners tend to struggle with the idea of ($) anyway; this may not make it much worse. I suspect good Haddocks will help alleviate this concern.</div><div dir="auto"><br></div><div dir="auto">3. Some type family and class instances may not be resolved under certain circumstances which I suspect occur very rarely in practice.</div><div dir="auto"><br></div><div dir="auto">    class C a where</div><div dir="auto">      m :: (a -> a) -> ()</div><div dir="auto">    instance C (a -> b) where</div><div dir="auto">      m _ = ()</div><div dir="auto">    test :: ()</div><div dir="auto">    test = m ($)</div><div dir="auto"><br></div><div dir="auto">Today, this compiles with no difficulties; with the proposed change, the user would have to supply a type signature to make it work:</div><div dir="auto"><br></div><div dir="auto">    test = m (($) :: (a -> b) -> (a -> b))<br><br></div><div>This can also change when an INCOHERENT instance is selected under similarly contrived circumstances, but those who use such generally deserve what they get.<br><br></div><div>David<br></div></div>
</div>