考虑以下GHCi的转录本,版本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]
如您所见,fmap
的类型推断为Functor f1 -> (a -> b) -> f2 a -> f2 b
。这是令人惊讶的,因为f1
和f2
应该是相同的类型变量,但是没有f1 ~ f2
约束。但是,如果您将fmap
应用于Functor map
类型Functor []
,则结果仍然符合预期的类型(a -> b) -> [a] -> [b]
。这里发生了什么?我希望fmap
具有类型Functor f -> (a -> b) -> f a -> f b
。
答案 0 :(得分:2)
我可以确认这个问题影响GHC 8.2.2但不影响8.0.2。 更新:看起来它已在8.4分支上修复。
它似乎是GHCi类型的签名显示错误,而不是真正的类型检查程序问题,因为如果您采用该程序:
{-# LANGUAGE RankNTypes #-}
module Inference where
data Functor f = Functor { fmap :: forall a b. (a -> b) -> f a -> f b }
并使用ghc -ddump-tc
进行编译,您可以看到GHC推断出正确的类型:
TYPE SIGNATURES
...
Inference.fmap ::
forall (f :: * -> *).
Inference.Functor f -> forall a b. (a -> b) -> f a -> f b
它似乎也不会影响GHC错误消息。如果添加以下行:
main = print Inference.fmap
生成包含类型的错误消息("没有(显示xxx)"的实例),您也看到正确的类型。