Haskell 无法推断(m~m1)

Haskell 无法推断(m~m1),haskell,Haskell,在GHC中编译此程序时: import Control.Monad f x = let g y = let h z = liftM not x in h 0 in g 0 我收到一个错误: test.hs:5:21: Could not deduce (m ~ m1) from the context (Monad m) bound by the inferred type of f :: Monad m => m Bool ->

在GHC中编译此程序时:

import Control.Monad

f x = let
  g y = let
    h z = liftM not x
    in h 0
  in g 0
我收到一个错误:

test.hs:5:21:
    Could not deduce (m ~ m1)
    from the context (Monad m)
      bound by the inferred type of f :: Monad m => m Bool -> m Bool
      at test.hs:(3,1)-(7,8)
    or from (m Bool ~ m1 Bool, Monad m1)
      bound by the inferred type of
               h :: (m Bool ~ m1 Bool, Monad m1) => t1 -> m1 Bool
      at test.hs:5:5-21
      `m' is a rigid type variable bound by
          the inferred type of f :: Monad m => m Bool -> m Bool
          at test.hs:3:1
      `m1' is a rigid type variable bound by
           the inferred type of
           h :: (m Bool ~ m1 Bool, Monad m1) => t1 -> m1 Bool
           at test.hs:5:5
    Expected type: m1 Bool
      Actual type: m Bool
    In the second argument of `liftM', namely `x'
    In the expression: liftM not x
    In an equation for `h': h z = liftM not x

为什么??另外,为
f
f::Monad m=>m Bool->m Bool
)提供显式类型签名会使错误消失。但根据错误消息,这与Haskell为
f
自动推断的类型完全相同

事实上,这很简单。
let
绑定变量的推断类型隐式地泛化为类型模式,因此在您的方式中有一个量词。
h
的一般类型为:

h :: forall a m. (Monad m) => a -> m Bool
f :: forall m. (Monad m) => m Bool -> m Bool
f
的一般类型为:

h :: forall a m. (Monad m) => a -> m Bool
f :: forall m. (Monad m) => m Bool -> m Bool
它们不是相同的
m
。如果您编写以下内容,您将得到基本相同的错误:

f :: (Monad m) => m Bool -> m Bool
f x = let
  g y = let
    h :: (Monad m) => a -> m Bool
    h z = liftM not x
    in h 0
  in g 0
您可以通过启用“作用域类型变量”扩展来修复它:

{-# LANGUAGE ScopedTypeVariables #-}

f :: forall m. (Monad m) => m Bool -> m Bool
f x = let
  g y = let
    h :: a -> m Bool
    h z = liftM not x
    in h 0
  in g 0

或者通过禁用带有“单态局部绑定”扩展的
let
-泛化,
monocalbinds

单态限制?单态限制仅适用于简单模式绑定,这里没有。无论如何,添加
-xnomonomomorphismrestriction
没有任何效果。我认为这与let泛化有关,因为错误会随着
-xmonocalbinds
消失,这并不是那么简单,因为对于
ghc,为什么
fx=let gy=liftM而不是g0中的x发生这种情况?
g
的类型也应该用同样的方法来概括。也许这是一个bug。在这种情况下,问题和答案是一个很好的例子和开始寻找的地方。