您好,我正在Haskell中编写一个类似C语言的静态类型语言的解释器。我想在执行代码之前执行类型检查,但是我遇到了一些问题。首先,下面是我的抽象语法中的一些类型定义:
newtype Ident = Ident String deriving (Eq,Ord,Show)
data Exp = {-- some other value constructors --} | EFuncWithParams Ident [Exp]
data Type = TInt | TDouble | {-- some other value constructors --} | TFunction [Exp]
type TCM a = ErrorT String (Reader Env) a
TCM用于报告错误并传递环境,例如:
typeof (EVar v) = do
env <- ask
case M.lookup v env of
Nothing -> throwError $ "undefined variable" ++ v ++ "\n"
Just t - > return t
现在我想检查表达式的类型,所以我有以下执行检查的函数:
typeof Exp :: Exp -> TCM Type
它是针对所有情况定义的,只有一个:
typeof (EFuncWithParams f l)
我被困在这里。我认为我应该做的是检查f的类型(我的意思是首先检查它是否真的是一个函数)并查看在f的定义中记录的参数类型是否匹配实际传递的参数类型。不幸的是,我是一个haskell新手,并不知道如何以正确的方式表达它。任何建议将受到高度赞赏:)
编辑: 好吧,我之前写的内容可能并不暗示,但EFuncWithParams Ident [Exp]实际上是一个函数调用(是的,我知道这有点误导)我希望能够像f(2 + 3)一样调用函数,a,b [0])这就是我使用TFunction [Exp]的原因。函数声明和定义是一个声明并定义:
data Function_def =
Func Type_specifier Declarator Compound_stm
deriving (Eq,Ord,Show)
其中声明者是:
data Declarator = FuncDec Ident Parameter_declarations
参数声明是Type_specifiers和Idents
的列表我认为我应该做的是在检查声明时将函数类型保存在地图中,然后在此处获取它。我的意思是我也有:
typeof_stm :: Stm -> TCM Type -- Function_def is a statement
问题是我有一个单独的函数用于类型检查语句,我怀疑一个函数使用的映射(例如typeof_stm)是否自动传递给另一个函数(例如typeof)。我认为没有办法实现这一点,但也许我错了。
答案 0 :(得分:3)
我认为你的功能类型是错误的。你有TFunction [Exp]
,它应该是TFunction [Type] Type
(参数类型列表和返回类型)。
函数调用的Typechecking代码看起来像
case ... of ...
EFuncWithParams ident args -> do
t <- typeof (EVar ident)
ts <- mapM typeof args
case t of
TFunction ps r -> if ts == ps
then return r
else throwError $ "parameter types do not match"
_ -> throwError $ "called id " ++ ident ++ " which is not a function"
这个伪代码可能不正确地进出monad,请耐心等待我,我没有你所有的代码所以我不能真正地检查我所做的事情。但总体方案是这样的。如果参数类型不匹配(哪些不匹配,或者参数数量可能错误),您可能希望提供更详细的错误报告。
答案 1 :(得分:1)
我对Haskell不熟练,我只是在OCaml和C ++中做过,但你要做的是递归调用每个参数的类型检查函数并检查它们是否对应。
我的意思是你必须输入类似
的东西FunCall ident, exp list
现在,您将在环境中拥有一个函数条目,其中包含相关参数类型,因此您需要确保的是:
ident
的函数typeof (exp1)
的每个参数,并检查返回的TCM Type
是否与相应参数相同这是应该如何运作的。在OCaml(有点类似于Haskell)中,我会做类似的事情:
match exp with
| FunCall ident, (param list) ->
(* get fundecl from ident *)
(* call check_params list_of_parameters, list_of_type_of_parameters *)
(* if check params return true then type check value of the function is the return value *)
let check_params list decl_list =
match list, decl_list with
| [], [] -> true
| p :: rp, d :: rd -> typeof(p) = d && check_params rp rd
| _ -> false
答案 2 :(得分:0)
EFuncWithParams Ident [Exp]
像您这样的语言通常需要在输入上使用类型注释,并且可能还需要在输出上使用类型注释。因此,如果您将此信息添加到该构造函数
EFuncWithparams { inType, outType :: Type
, funcInput :: Ident
, funcBody :: [Expr] }
现在要进行类型检查,你只需:
funcInput
与inType
的绑定添加到您的类型环境funcBody
的类型outType
匹配。您还应检查函数应用程序,以确保输入与函数inType
匹配,并根据outType
正确使用结果。