I’m implementing a type checker in the Lisp macro system and I wanted to do a sanity check by analyzing the same programs in Haskell.
(I’ve enabled RankNTypes and ScopedTypeVariables)
I was confounded by Haskell rejecting this program:
f :: (forall r. r -> r) -> Int
f = g
g :: (String -> String) -> Int
g _ = 1337
I scratched my head for quite a while until I discovered that this program is not rejected:
f :: (forall r. r -> r) -> Int
f x = g x
g :: (String -> String) -> Int
g _ = 1337
Same goes for this. Rejected:
c :: Char
c = f g
f :: ((forall r. r -> r) -> Int) -> Char
f _ = 'x'
g :: (String -> String) -> Int
g _ = 1337
But this is accepted
c :: Char
c = f (\x -> g x)
f :: ((forall r. r -> r) -> Int) -> Char
f _ = 'x'
g :: (String -> String) -> Int
g _ = 1337
I don’t know if it’s a bug technically but it’s still weird. Maybe there’s an underlying problem lurking in the background of the Haskell type checker, waiting to pounce on you.
I’m just smashing parentheses together until they behave but as far as I can tell, I don’t have to worry about “deep subsumption” being a problem. Maybe it will be a problem later.
Assuming you use GHC, what is the version you used and what exactly is the error message of the rejected programs?
I ask because you are not the first one to fall into this trap, and we could help improve GHCs error messages so that people do not have to ask in forums to understand what is going on.
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
main :: IO ()
main = putStrLn "yo"
c :: Char
c = f g
f :: ((forall r. r -> r) -> Int) -> Char
f _ = 'x'
g :: (String -> String) -> Int
g _ = 1337
Main.hs:8:7: error: [GHC-83865]
• Couldn't match type: String -> String
with: forall r. r -> r
Expected: (forall r. r -> r) -> Int
Actual: (String -> String) -> Int
• In the first argument of ‘f’, namely ‘g’
In the expression: f g
In an equation for ‘c’: c = f g
|
8 | c = f g
I thought it wouldn’t really add anything; the intersection of people who’d encounter this error and people who would be much more comfortable with “eta expansion” instead of “explicit function application” seems pretty slim to me.