3

嗨,我正在用 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)。我认为这不会发生,但也许我错了。

4

3 回答 3

3

我认为你的函数类型是错误的。你有它TFunction [Exp],它应该是TFunction [Type] Type(参数类型列表和返回类型)。

函数调用的类型检查代码看起来像

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,请多多包涵,我没有你的所有代码,所以我无法真正检查我所做的事情。但整体方案是这样的。如果参数类型不匹配(哪些不匹配,或者参数数量错误),您可能需要提供更详细的错误报告。

于 2012-04-19T15:53:38.363 回答
1

I'm not practical with Haskell, I just did it in OCaml and in C++ but what you are going to do is to call the type checker function recursively on each parameter and check if they do correspond.

What I mean is that you'll have to type check something that is like

FunCall ident, exp list

Now you'll have in the environment an entry for the function with the types of parameters associated so what you need to ensure in order is that:

  • function named ident does exist in the environment
  • the number of parameters is equal to the definition (this can be done implicitly by the param checking function, see below)
  • for every parameter you call typeof (exp1) and you check that the returned TCM Type is the same of the corresponding parameter

This is how it should work. In OCaml (which is somewhat similar to Haskell) I would do something like:

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
于 2012-04-19T15:18:57.700 回答
0
EFuncWithParams Ident [Exp]

像您这样的语言通常需要在输入上使用类型注释,并且可能还需要在输出上使用类型注释。因此,如果您将此信息添加到该构造函数

EFuncWithparams { inType, outType :: Type
                , funcInput :: Ident
                , funcBody :: [Expr] }

现在要对它进行类型检查,您只需:

  1. 将 to的绑定添加funcInputinType您的类型环境
  2. funcBody用新的类型环境确定类型
  3. 确保它与outType.

您还应该检查函数应用程序以确保输入与函数的 匹配inType,并且根据其正确使用结果outType

于 2012-04-19T15:29:39.773 回答