Search code examples
purescript

Strange type inference behavior


I'm trying to understand why purescript is unable to properly infer type for map parameter in this simple code:

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

Here is my error message:

  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.

However, it works if I specify the type manually:

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

Why it doesn't want to infer this type automatically even it's already provided in function signature?


Solution

  • The current compiler has no way of modeling functional dependencies, which are used in Haskell and the mtl library to capture the relationship between the two type arguments in MonadState.

    This means that the compiler can't figure out that the two state types have to be the same (that is, if we find an instance of MonadState for StateT (Maybe Int) Identity, the state type is forced to be Maybe Int).

    For now, one solution is to add a type annotation:

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