我在 Haskell 中遇到了模棱两可的类型问题。我从以下内容开始:
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
然后当我尝试在 ghci 中运行以下命令时:
runStateT getNextState Blank
我得到:
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)
...
我认为这是在抱怨我的 getNextState 函数的默认实现没有指定具体类型,所以我尝试了以下方法:
getNextState :: GameState b => GameStateMonad a (Maybe b)
getNextState = return (Nothing :: Maybe Blank)
不幸的是,我在编译时遇到了这个错误:
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
...
但是我发现在调用 getNext 状态时添加类型签名可以让代码运行:
runStateT (getNextState :: GameStateMonad Blank (Maybe Blank)) Blank
不幸的是,这阻止了我编写通用代码来处理游戏状态。这对我来说也没什么意义。如果在返回后必须给它一个显式类型,那么返回多态类型有什么意义?原来的问题也让我很困惑,因为我可以制作如下函数:
test :: Num a => Maybe a
test = Nothing
并且运行它没有问题。这不应该抱怨像我的原始代码这样的模棱两可的类型吗?同样,当给返回值一个显式类型时,我无法编译它,就像以前一样:
test :: Num a => Maybe a
test = Nothing :: Maybe Int
我不明白为什么这是一个问题。Int 是 Num 类型的实例,因此函数的类型是正确的。
我有四个问题:
为什么在返回类型类的元素时给出显式类型会导致编译错误?
为什么在 getNextState 内部返回一个模棱两可的 Maybe 值会导致错误,但在 test 内部却不会?
为什么在没有我对返回的多态数据调用函数的情况下会发生此错误,如此处所述?
在上面的链接中,答案提到“[你得到这个错误]因为你有一些产生多态结果的东西,然后应用一个函数,该函数接受一个多态参数到该结果,这样中间值的类型是未知的”。这不是意味着返回多态结果的函数本质上是无用的吗?
谢谢。