为什么`让foo =(fmap.const)`失败"因为使用`fmap'而没有(Functor f0)的实例?

Lau*_*ves 7 haskell type-inference

在ghci,我可以这样做:

ghci> (fmap . const) 5 [1,2,3,4,5]
[5,5,5,5,5]
Run Code Online (Sandbox Code Playgroud)

但如果我尝试将子表达式提取(fmap . const)到变量中,我会收到错误:

ghci> let foo = (fmap . const)

<interactive>:3:12:
    No instance for (Functor f0) arising from a use of `fmap'
    The type variable `f0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance Functor ((,) a) -- Defined in `GHC.Base'
      instance Functor ((->) r) -- Defined in `GHC.Base'
      instance Functor IO -- Defined in `GHC.Base'
      ...plus two others
    In the first argument of `(.)', namely `fmap'
    In the expression: (fmap . const)
    In an equation for `foo': foo = (fmap . const)
Run Code Online (Sandbox Code Playgroud)

我认为这可能意味着GHC的类型推断在某种程度上失败了,但是当我向ghci询问subexpresiion的类型时,它没有问题:

ghci> :t (fmap . const)
(fmap . const) :: Functor f => b -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

那么这里发生了什么?有没有办法将这个子表达式提取到变量中?为什么不直截了当的let工作?

更新:

"什么是单态限制"可能是一个好的东西,在答案中链接(即:"另见......"),但这不是该问题的重复,除非StackOverflow已成为某种奇怪的版本游戏节目Jeopardy.当我问这个问题时,我已经知道单态性限制了,但对我来说,MR是导致我收到错误的原因一点也不明显.

在这方面,这个问题的答案没有帮助.它说"这意味着,在某些情况下,如果你的类型不明确......编译器将选择将该类型实例化为不模糊的东西",这与此处发生的情况几乎相反(MR正在产生歧义,不要删除它.)

Dir*_*ple 5

这是可怕的单态限制.如果你运行:set -XNoMonomorphismRestriction它会工作.您也可以使用这样的显式类型签名来定义它

foo :: Functor f => b -> f a -> f b
foo = fmap . const
Run Code Online (Sandbox Code Playgroud)

  • @dfeuer:在这种情况下,类型签名适用于表达式`fmap.const`,并且仍然没有`foo`的类型签名,这是应用限制的标识符.从本质上讲,这种类型的签名不会告诉类型检查器任何新的东西,而直接向`foo`添加类型签名确实会告诉类型检查器一些新的东西(即"我真的有意为这是多态的,即使它没有'看起来像一个函数") (3认同)
  • 这是他们出现的常见情况,但还有许多其他原因.大多数都更合法,所以你不能只是假设. (2认同)