1

我正在爲我參加的課程編寫一個小型編譯器。所以我開始寫這個monad變換器來處理類型檢查,但是得到了一個非常神祕的類型錯誤。涉及函數依賴的東西,我不太清楚。 從程序的小摘錄,可以重現錯誤:這個類型檢查錯誤是什麼意思?

import Control.Monad.RWS.Lazy 
import qualified Data.Map as M 
import Control.Applicative 

--Placeholders for other data types. 
data TypeError = TypeError 
data Ident = Ident String 
data Type = Type 

type Typer a = RWS FunctionTable [TypeError] IdentTable a 

type FunctionTable = M.Map Ident Type 

type IdentTable = [M.Map Ident Type] 

emptyIdents :: IdentTable 
emptyIdents = [] 

getIdent :: Ident -> Typer (Maybe Type) 
getIdent id = getIdent' id <$> get 

getIdent' :: Ident -> IdentTable -> Maybe Type 
getIdent' _ [] = Nothing 
getIdent' id (x:xs) = 
    case M.lookup id x of 
    Just t -> Just t 
    Nothing -> getIdent' id xs 

putIdent :: Ident -> Type -> Typer() 
putIdent id ty = modify $ \xs -> case xs of 
    [] -> [M.singleton id ty] 
    (x:xs) -> (M.insert id ty x) : xs 

scopeEnter :: Typer() 
scopeEnter = modify $ \ids -> emptyIdents : ids 

scopeExit :: Typer() 
scopeExit = modify tail 

和實際的消息:

[1 of 1] Compiling Main    (ErrorExample.hs, interpreted) 

ErrorExample.hs:30:22: 
    Couldn't match type `M.Map Ident Type' with `Type' 
    When using functional dependencies to combine 
     MonadState 
     [[M.Map Ident Type]] 
     (RWST 
      (M.Map Ident Type) 
      [TypeError] 
      [M.Map Ident Type] 
      transformers-0.2.2.0:Data.Functor.Identity.Identity), 
     arising from a use of `modify' at ErrorExample.hs:35:18-23 
     MonadState 
     [M.Map Ident Type] 
     (RWST 
      (M.Map Ident Type) 
      [TypeError] 
      [M.Map Ident Type] 
      transformers-0.2.2.0:Data.Functor.Identity.Identity), 
     arising from a use of `modify' at ErrorExample.hs:30:22-27 
    In the expression: modify 
    In the expression: 
     modify 
     $ \ xs 
      -> case xs of { 
       [] -> [...] 
       (x : xs) -> (M.insert id ty x) : xs } 

ErrorExample.hs:30:22: 
    Couldn't match type `[]' with `M.Map Ident' 
    When using functional dependencies to combine 
     MonadState 
     [[M.Map Ident Type]] 
     (RWST 
      (M.Map Ident Type) 
      [TypeError] 
      [M.Map Ident Type] 
      transformers-0.2.2.0:Data.Functor.Identity.Identity), 
     arising from a use of `modify' at ErrorExample.hs:35:18-23 
     MonadState 
     [M.Map Ident Type] 
     (RWST 
      (M.Map Ident Type) 
      [TypeError] 
      [M.Map Ident Type] 
      transformers-0.2.2.0:Data.Functor.Identity.Identity), 
     arising from a use of `modify' at ErrorExample.hs:30:22-27 
    In the expression: modify 
    In the expression: 
     modify 
     $ \ xs 
      -> case xs of { 
       [] -> [...] 
       (x : xs) -> (M.insert id ty x) : xs } 

ErrorExample.hs:35:18: 
    Couldn't match type `Type' with `M.Map Ident Type' 
    When using functional dependencies to combine 
     MonadState s (RWST r w s m), 
     arising from the dependency `m -> s' 
     in the instance declaration in `Control.Monad.State.Class' 
     MonadState 
     [[M.Map Ident Type]] 
     (RWST 
      (M.Map Ident Type) 
      [TypeError] 
      [M.Map Ident Type] 
      transformers-0.2.2.0:Data.Functor.Identity.Identity), 
     arising from a use of `modify' at ErrorExample.hs:35:18-23 
    In the expression: modify 
    In the expression: modify $ \ ids -> emptyIdents : ids 

ErrorExample.hs:35:18: 
    Couldn't match type `M.Map Ident' with `[]' 
    When using functional dependencies to combine 
     MonadState s (RWST r w s m), 
     arising from the dependency `m -> s' 
     in the instance declaration in `Control.Monad.State.Class' 
     MonadState 
     [[M.Map Ident Type]] 
     (RWST 
      (M.Map Ident Type) 
      [TypeError] 
      [M.Map Ident Type] 
      transformers-0.2.2.0:Data.Functor.Identity.Identity), 
     arising from a use of `modify' at ErrorExample.hs:35:18-23 
    In the expression: modify 
    In the expression: modify $ \ ids -> emptyIdents : ids 
Failed, modules loaded: none. 
Leaving GHCi. 

回答

4

這是一個非常糟糕的錯誤消息。原因是由於國家的類型不匹配。你的代碼試圖混合[M.Map Ident Type]和[[M.Map Ident Type]]。

如果手動內聯emptyIdents調入scopeEnter它看起來像這樣:

scopeEnter :: Typer() 
scopeEnter = modify $ \ids -> [] : ids 

...這沒有多大意義的[M.Map Ident Type]。將其與進行類型檢測的版本進行比較:

scopeEnter :: Typer() 
scopeEnter = modify $ \ids -> M.empty : ids