Pattern matching inferred type

128 views Asked by At

Why doesn't the below type-check? The type of _ is inferred as Double.

{-# LANGUAGE ScopedTypeVariables, Rank2Types #-}

module Main (main) where

data D a = D a

main =
  let
    n = D (1 :: forall a. (Floating a) => a)
  in
    case n of
      D (_ :: forall a. (Floating a) => a) -> return ()
1

There are 1 answers

0
Alexis King On BEST ANSWER

It appears that the type you are expecting for n is D (forall a. (Floating a) => a), but that is emphatically not the type that is inferred. In fact, if you try and add that type annotation to n, you will find that GHC will loudly complain. Such a type would require GHC to support impredicative polymorphism, and it currently does not (for more information on what that is and why it is complicated, see What is predicativity?).

The type that is actually inferred for n is D Double. This is actually the result of two things at play: the dreaded monomorphism restriction and Haskell’s type defaulting rules. Due to the monomorphism restriction, n must be inferred to be a monomorphic type (since it is not syntactically a function and does not have an explicit type annotation). For this reason, D 1 would be ambiguous, since 1 :: forall a. (Floating a) => a is polymorphic. However, in this case, Haskell has defaulting rules for numeric types, mostly to avoid the need to resolve ambiguities due to Haskell’s polymorphic number literals.

Since you have explicitly added a type annotation to 1 to make it Floating, then Haskell applies its default rule for floating-point types and defaults to Double. Therefore, the type of n is inferred to be D Double.

If you disable the monomorphism restriction, then the type of n would be the slightly more interesting type forall a. Floating a => D a, but that is the simpler universally quantified type rather than the existentially quantified one that you want.