Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Surprising type inference for named field in Haskell

Consider the following transcript of GHCi, version 8.2.2:

GHCi, version 8.2.2: http://www.haskell.org/ghc/  :? for help
Prelude> :set -XRankNTypes
Prelude> data Functor f = Functor { fmap :: forall a b. (a -> b) -> f a -> f b }
Prelude> :t fmap
fmap :: Functor f1 -> (a -> b) -> f2 a -> f2 b
Prelude> :t Functor map
Functor map :: Functor []
Prelude> :t fmap (Functor map)
fmap (Functor map) :: (a -> b) -> [a] -> [b]

As you can see, the type of fmap is inferred as Functor f1 -> (a -> b) -> f2 a -> f2 b. This is surprising because f1 and f2 are supposed to be the same type variable but there's no f1 ~ f2 constraint. Nevertheless, if you apply fmap to Functor map which has the type Functor [], the result still has the type (a -> b) -> [a] -> [b] as expected. What's going on here? I would have expected fmap to have the type Functor f -> (a -> b) -> f a -> f b.

like image 733
Aadit M Shah Avatar asked Jan 27 '18 01:01

Aadit M Shah


1 Answers

I can confirm that this issue affects GHC 8.2.2 but not 8.0.2. Update: It looks like it's been fixed on the 8.4 branch.

It appears to be a GHCi type signature display bug, rather than a real type checker issue, since if you take the program:

{-# LANGUAGE RankNTypes #-}
module Inference where
data Functor f = Functor { fmap :: forall a b. (a -> b) -> f a -> f b }

and compile it with ghc -ddump-tc, you can see that GHC infers the correct type:

TYPE SIGNATURES
  ...
  Inference.fmap ::
    forall (f :: * -> *).
    Inference.Functor f -> forall a b. (a -> b) -> f a -> f b

It also doesn't seem to affect GHC error messages. If you add the line:

main = print Inference.fmap

to produce an error message that includes the type ("No instance for (Show xxx)"), you also see the correct type.

like image 154
K. A. Buhr Avatar answered Sep 30 '22 05:09

K. A. Buhr