I am having trouble with ambiguous types in Haskell. I started out with the following:
module GameState
( GameState(..)
, GameStateMonad
, module Control.Monad.Trans
, module Control.Monad.Trans.State.Lazy
, Blank(..)
) where
import Control.Monad.Trans
import Control.Monad.Trans.State.Lazy
type GameStateMonad a b = StateT a IO b
class GameState a where
update :: Double -> GameStateMonad a ()
update deltaTime = return ()
draw :: GameStateMonad a ()
draw = return ()
getNextState :: GameState b => GameStateMonad a (Maybe b)
getNextState = return Nothing
isStateFinished :: GameStateMonad a Bool
isStateFinished = return True
-- This is just a dummy data and instance declaration to demonstrate the error
data Blank = Blank
instance GameState Blank
Then when I try to run the following in ghci:
runStateT getNextState Blank
I get:
Ambiguous type variable `b0' in the constraint:
(GameState b0) arising from a use of `getNextState'
Probable fix: add a type signature that fixes these type variable(s)
...
I thought it was complaining that my default implementation of the getNextState function didn't specify a concrete type, so I tried the following:
getNextState :: GameState b => GameStateMonad a (Maybe b)
getNextState = return (Nothing :: Maybe Blank)
Unfortunately I got this error while compiling:
Could not deduce (b ~ Blank)
from the context (GameState a)
bound by the class declaration for `GameState'
at GameState.hs:(14,1)-(25,33)
or from (GameState b)
bound by the type signature for
getNextState :: GameState b => GameStateMonad a (Maybe b)
at GameState.hs:22:5-50
`b' is a rigid type variable bound by
the type signature for
getNextState :: GameState b => GameStateMonad a (Maybe b)
at GameState.hs:22:5
...
But I found that adding a type signature when I call getNext state allows the code to run:
runStateT (getNextState :: GameStateMonad Blank (Maybe Blank)) Blank
Unfortunately this stops me from making generic code to handle game states. It also makes little sense to me. What's the point in returning a polymorphic type if you have to give it an explicit type after it's returned? The original issue is also really confusing to me because I can make a function as follows:
test :: Num a => Maybe a
test = Nothing
And have no problems running it. Shouldn't this complain about ambiguous types like my original code? Also when giving the return value an explicit type I cannot compile it, like before:
test :: Num a => Maybe a
test = Nothing :: Maybe Int
I don't see why this is a problem. Int is an instance of type Num so the type of the function is correct.
I have four questions:
Why does giving an explicit type when returning an element of a typeclass cause a compile error?
Why does returning an ambiguous Maybe value inside of getNextState cause an error but inside test it does not?
Why does this error occur without me calling a function on the returned polymorphic data, as explained here?
In the link above, the answer mentions that "[you get this error] because you have something that produces a polymorphic result, then apply a function that takes a polymorphic argument to that result, such that the intermediate value's type is unknown". Doesn't this mean that functions that return a polymorphic result are essentially useless?
Thanks.