I was trying to write a function that can get the data that a newtype wraps.
newtype Person = Person {name :: String, age :: Int}
getRecord :: forall r. Newtype Person r => Person -> r
getRecord (Person p) = p
This fails to compile and complains
Could not match type
{ age :: Int
, name :: String
}
with type
r0
while checking that type { age :: Int
, name :: String
}
is at least as general as type r0
while checking that expression p
has type r0
in value declaration getRecord
But when I do
getRecord :: forall r. Newtype Person r => Person -> r
getRecord = unwrap
It works fine !! My Question is why it can't infer the type the first time?
The newtype type class is defined like,
class (Coercible t a) <= Newtype t a | t -> a
which means it can infer the a
when it knows what t
is. Then why its not working the first time.
Constraint solving happens when calling the function, but not when defining one.
At call site, the compiler will solve the Newtype Person r
constraint and figure out that r ~ { age :: Int, name :: String }
, so you can use its fields.
But at definition site, the compiler doesn't do that. There, it's just some unknown type r
. And since it's unknown, the compiler can't in good faith tell that r ~ { age :: Int, name :: String }
, so there is a type mismatch.
Using unwrap
works, because there the type r
doesn't need to be known. Whatever it is, it's just passed straight to unwrap
, and your function doesn't need to know anything about it.
Why does the compiler not do constraint solving at definition site? I mean it technically could, but that would be kinda useless anyway: after all, if you already know the type, just write it out:
getRecord :: Person -> { age :: Int, name :: String }
getRecord (Person p) = p