在我正在编写的玩具编译器中,我想使用通用递归数据类型来表示抽象语法树(AST),可能用一些属性进行注释。
解析器为表达式构建 AST,并用源代码中的位置进行注释。
语义分析器采用带有位置注释的 AST,并生成一个 monad,该 monad 在运行时返回相应的带有类型信息注释的 AST。
语义分析器的目的是对表达式进行类型检查,报告过程中发现的任何错误。表达式的计算类型应该用作原始树中的注释,以便最后每个树节点都将使用其类型进行注释。
完全实现语义分析器后,将使用 RWS monad,因为它需要一个环境来编译 let 表达式和变量,将生成发现错误的日志,并且表达式语言中的一些新结构将需要编译状态.
在尝试编写语义分析器时,我遇到了 Haskell 类型系统的问题。以下代码演示了我遇到的问题类型:
{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
module Lang0 where
import Prelude hiding (foldr1,mapM,exp)
import Data.Foldable (Foldable)
import Data.Traversable (Traversable)
import Control.Monad.RWS (runRWS)
newtype Fix f = In { out :: f (Fix f) }
deriving instance Show (f (Fix f)) => Show (Fix f)
data Ann x f a = Ann { attr :: x -- ^ the annotation
, unAnn :: f a -- ^ the original functor
}
deriving (Eq,Ord,Show,Functor,Foldable,Traversable)
data Range = Range Int Int
instance Show Range where
show (Range a b) = show a ++ "-" ++ show b
type Name = String
data BinOp
= Add | Sub | Mul | Div
| Eq | Ne | Gt | Ge | Lt | Le
| Con | Dis
deriving (Eq,Show)
data ExpF r
= Log Bool
| Num Double
| Var Name
| Neg r
| Bin BinOp r r
| Let Name r r
deriving (Eq,Show,Functor,Foldable,Traversable)
data Type = NUMERIC | LOGIC deriving (Eq,Show)
newtype Exp = Exp { runExp :: Fix ExpF } deriving (Show)
newtype ExpPos = ExpPos { runExpPos :: Fix (Ann Range ExpF) } deriving (Show)
newtype ExpType = ExpType { runExpType :: Fix (Ann ExpType ExpF) } deriving (Show)
type Env = [(Name, Type)]
type Log = [(Range, String)]
semantExp :: Monad m => Fix (Ann Range ExpF) -> m (Fix (Ann Type ExpF))
semantExp (In (Ann pos exp)) =
case exp of
Num _ -> return (In (Ann NUMERIC exp))
_ -> error "unimplemented"
e1 :: ExpPos
e1 = ExpPos (In (Ann (Range 1 2) (Num 8)))
main :: IO ()
main = print (runRWS (semantExp (runExpPos e1)) [] ())
当将此代码提供给 ghc 编译器时,我得到以下信息:
$ ghc --make Lang0
[1 of 1] Compiling Lang0 ( Lang0.hs, Lang0.o )
Lang0.hs:60:38:
Couldn't match type `Range' with `Type'
Expected type: ExpF (Fix (Ann Type ExpF))
Actual type: ExpF (Fix (Ann Range ExpF))
In the second argument of `Ann', namely `exp'
In the first argument of `In', namely `(Ann NUMERIC exp)'
In the first argument of `return', namely `(In (Ann NUMERIC exp))'
为什么编译器希望参数中的注释和结果 AST 的类型相同?
有关如何解决此问题的任何线索?
附加观察:如果没有 的类型注释semantExp
,编译器会为其推断以下类型:
semantExp
:: Monad m => Fix (Ann Type ExpF) -> m (Fix (Ann Type ExpF))
为什么推断的类型在结果单子的参数中具有相同的注释类型?