Haskell's ($) is a magic operator?

Haskell

Haskell Problem Overview


Say I have the following functions:

infixr 0 <|

{-# INLINE (<|) #-}
(<|) :: (a -> b) -> a -> b
f <| x = f x

foo :: a -> (forall b. b -> b) -> a
foo x f = f x

The following does not type check:

ghci> foo 3 <| id

Couldn't match expected type `forall b. b -> b'
            with actual type `a0 -> a0'
In the second argument of `(<|)', namely `id'
In the expression: f 3 <| id
In an equation for `it': it = f 3 <| id

However, foo 3 $ id does.

The definition of (<|) is (as far as I know) identical to the definition of ($). I pretty much ripped out the definition from the base library sources, and changed every instance of ($) to (<|). Compiler magic?

Haskell Solutions


Solution 1 - Haskell

Yes, there's a small amount of compiler magic around ($) to handle impredicative types. It was introduced because everyone expects

runST $ do
  foo
  bar
  baz

to typecheck, but it cannot normally. For more details see here (search runST), this email, and this email. The short of it is that there's actually a special rule in the type-checker specifically for ($) which gives it the ability to resolve the common case of impredicative types.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionYellPikaView Question on Stackoverflow
Solution 1 - HaskellJ. AbrahamsonView Answer on Stackoverflow