奇怪的类型推断行为

Strange type inference behavior

我试图理解为什么 purescript 无法在这个简单的代码中正确推断 map 参数的类型:

maybeInc :: String -> StateT (Maybe Int) Identity Unit
maybeInc "a" = modify $ map (1 +)
maybeInc _ = return unit

这是我的错误信息:

  No type class instance was found for

    Control.Monad.State.Class.MonadState (_0 Int)
                                         (StateT (Maybe Int) Identity)

  The instance head contains unknown type variables. Consider adding a type annotation.

但是,如果我手动指定类型,它会起作用:

maybeInc "a" = modify $ \(m :: Maybe Int) -> map (1 +) m

为什么它不想自动推断这种类型,即使它已经在函数签名中提供了?

当前的编译器无法对函数依赖建模,Haskell 和 mtl 库使用函数依赖来捕获 MonadState 中两个类型参数之间的关系。

这意味着编译器无法确定两个状态类型必须相同(也就是说,如果我们为 StateT (Maybe Int) Identity 找到 MonadState 的实例,则状态类型被强制为 Maybe Int).

目前,一种解决方案是添加类型注释:

maybeInc :: String -> StateT (Maybe Int) Identity Unit
maybeInc "a" = modify modifier
  where
    modifier :: Maybe Int -> Maybe Int
    modifier = map (1 +)
maybeInc _ = return unit