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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With