Haskell中命名字段的令人惊讶的类型推断

Aad*_*hah 6 haskell type-inference

请考虑以下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]
Run Code Online (Sandbox Code Playgroud)

如您所见,fmap推断的类型为Functor f1 -> (a -> b) -> f2 a -> f2 b.因为这是令人惊讶的f1f2应该是同一类型的变量,但没有f1 ~ f2约束.不过,如果你适用fmapFunctor map具有类型Functor [],结果仍然有型(a -> b) -> [a] -> [b]如预期.这里发生了什么?我本来期望fmap有这种类型Functor f -> (a -> b) -> f a -> f b.

K. *_*uhr 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 }
Run Code Online (Sandbox Code Playgroud)

并用 编译它ghc -ddump-tc,你可以看到 GHC 推断出正确的类型:

TYPE SIGNATURES
  ...
  Inference.fmap ::
    forall (f :: * -> *).
    Inference.Functor f -> forall a b. (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

它似乎也不会影响 GHC 错误消息。如果添加以下行:

main = print Inference.fmap
Run Code Online (Sandbox Code Playgroud)

要生成包含类型的错误消息(“No instance for (Show xxx)”),您还会看到正确的类型。