浏览代码

progress on gradual for python

Jeremy Siek 3 年之前
父节点
当前提交
69655c5255
共有 1 个文件被更改,包括 233 次插入40 次删除
  1. 233 40
      book.tex

+ 233 - 40
book.tex

@@ -18618,7 +18618,7 @@ are allowed so long as the types are \emph{consistent}, that is, they
 are equal except in places where there is an \code{Any} type. The type
 \code{Any} is consistent with every other type.
 Figure~\ref{fig:consistent} defines the
-\racket{\code{consistent?}}\python{\code{consistent}} predicate.
+\racket{\code{consistent?}}\python{\code{consistent}} method.
 Returning to the \code{map} example of
 Figure~\ref{fig:gradual-map}, the \code{inc} function has type
 \racket{\code{(Any -> Any)}}\python{\code{Callable[[Any],Any]}}
@@ -18648,24 +18648,24 @@ because the two types are consistent.
 \fi}
 {\if\edition\pythonEd
 \begin{lstlisting}
-def consistent(self, t1, t2):
-    match (t1, t2):
-      case (AnyType(), _):
-        return True
-      case (_, AnyType()):
-        return True
-      case (FunctionType(ps1, rt1), FunctionType(ps2, rt2)):
-        return all([consistent(p1, p2) for (p1,p2) in zip(ps1,ps2)]) \
-            and consistent(rt1, rt2)
-      case (TupleType(ts1), TupleType(ts2)):
-        return all([consistent(ty1, ty2) for (ty1,ty2) in zip(ts1,ts2)])
-      case (_, _):
-        return t1 == t2
+  def consistent(self, t1, t2):
+      match (t1, t2):
+        case (AnyType(), _):
+          return True
+        case (_, AnyType()):
+          return True
+        case (FunctionType(ps1, rt1), FunctionType(ps2, rt2)):
+          return all([self.consistent(p1, p2) for (p1,p2) in zip(ps1,ps2)]) \
+              and consistent(rt1, rt2)
+        case (TupleType(ts1), TupleType(ts2)):
+          return all([self.consistent(ty1, ty2) for (ty1,ty2) in zip(ts1,ts2)])
+        case (_, _):
+          return t1 == t2
 \end{lstlisting}  
   \fi}
   \end{tcolorbox}
 
-  \caption{The consistency predicate on types.}
+  \caption{The consistency method on types.}
 \label{fig:consistent}
 \end{figure}
 
@@ -18807,11 +18807,226 @@ print(t[1])
 \end{figure}
 
 
+{\if\edition\pythonEd        
+\begin{figure}[tbp]
+\begin{tcolorbox}[colback=white]  
+\begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
+class TypeCheckLgrad(TypeCheckLlambda):
+  def type_check_exp(self, e, env):
+    match e:
+      case Name(id):
+        return env[id]
+      case Constant(value) if value is True or value is False:
+        return BoolType()
+      case Constant(value) if isinstance(value, int):
+        return IntType()
+      case Call(Name('input_int'), []):
+        return IntType()
+      case BinOp(left, op, right) if op == Add() or op == Sub():
+        left_type = self.type_check_exp(left, env)
+        self.check_consistent(left_type, IntType(), left)
+        right_type = self.type_check_exp(right, env)
+        self.check_consistent(right_type, IntType(), right)
+        return IntType()
+      case UnaryOp(USub(), v):
+        ty = self.type_check_exp(v, env)
+        self.check_consistent(ty, IntType(), v)
+        return IntType()
+      case IfExp(test, body, orelse):
+        test_t = self.type_check_exp(test, env)
+        self.check_consistent(test_t, BoolType(), test)
+        body_t = self.type_check_exp(body, env)
+        orelse_t = self.type_check_exp(orelse, env)
+        self.check_consistent(body_t, orelse_t, e)
+        return self.join_types(body_t, orelse_t)
+      case UnaryOp(Not(), v):
+        ty = self.type_check_exp(v, env)
+        self.check_consistent(ty, BoolType(), v)
+        return BoolType()
+      case BoolOp(op, values):
+        left = values[0]; right = values[1]
+        left_type = self.type_check_exp(left, env)
+        self.check_consistent(left_type, BoolType(), left)
+        right_type = self.type_check_exp(right, env)
+        self.check_consistent(right_type, BoolType(), right)
+        return BoolType()
+      case Compare(left, [cmp], [right]) \
+          if isinstance(cmp, Eq) or isinstance(cmp, NotEq):
+        left_type = self.type_check_exp(left, env)
+        right_type = self.type_check_exp(right, env)
+        self.check_consistent(left_type, right_type, e)
+        return BoolType()
+      case Compare(left, [cmp], [right]) \
+          if isinstance(cmp, Lt()) or isinstance(cmp, LtE()) \
+             or isinstance(cmp, Gt()) or isinstance(cmp, GtE()):
+        left_type = self.type_check_exp(left, env)
+        self.check_consistent(left_type, IntType(), left)
+        right_type = self.type_check_exp(right, env)
+        self.check_consistent(right_type, IntType(), right)
+        return BoolType()
+      case Compare(left, [cmp], [right]) if isinstance(cmp, Is):
+        left_type = self.type_check_exp(left, env)
+        right_type = self.type_check_exp(right, env)
+        self.check_consistent(left_type, right_type, e)
+        return BoolType()
+      case Call(func, args):
+        func_t = self.type_check_exp(func, env)
+        args_t = unzip([self.type_check_exp(arg, env) for arg in args])
+        match func_t:
+          case FunctionType(params_t, return_t):
+            for (arg_t, param_t) in zip(args_t, params_t):
+                self.check_consistent(param_t, arg_t, e)
+            return return_t
+          case AnyType():
+            return AnyType()
+          case _:
+            raise Exception('type_check_exp: in call, unexpected ' + repr(func_t))
+      case _:
+        raise Exception('type_check_exp: unexpected ' + repr(e))
+\end{lstlisting}
+\end{tcolorbox}
+
+\caption{Type checker for the \LangGrad{} language, part 1.}
+\label{fig:type-check-Lgradual-1}
+\end{figure}
+
+\begin{figure}[tbp]
+\begin{tcolorbox}[colback=white]  
+\begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
+      case Tuple(es, Load()):
+        ts = unzip([self.type_check_exp(e, env) for e in es])
+        return TupleType(ts)
+      case Subscript(tup, Constant(index), Load()) if isinstance(index,int)::
+        tup_ty = self.type_check_exp(tup, env)
+        match tup_ty:
+          case TupleType(ts):
+            return ts[index]
+          case AnyType():
+            return AnyType()
+          case _:
+            raise Exception('subscript expected a tuple, not ' + repr(tup_ty))
+      case Subscript(tup, index, Load()):
+        tup_ty = self.type_check_exp(tup, env)
+        index_ty = self.type_check_exp(index, env)
+        self.check_consistent(index_ty, IntType(), index)
+        match tup_ty:
+          case TupleType(ts):
+            return AnyType()
+          case AnyType():
+            return AnyType()
+          case _:
+            raise Exception('subscript a tuple, not ' + repr(tup_ty))
+      case Call(Name('len'), [tup]):
+        tup_t = self.type_check_exp(tup, env)
+        match tup_t:
+          case TupleType(ts):
+            return IntType()
+          case AnyType():
+            return IntType()
+          case _:
+            raise Exception('len expected a tuple, not ' + repr(tup_t))
+
+  def check_exp(self, e, ty, env):
+    match e:
+      case Lambda(params, body):
+        match ty:
+          case FunctionType(params_t, return_t):
+            new_env = {x:t for (x,t) in env.items()}
+            for (p,t) in zip(new_params, params_t):
+                new_env[p] = t
+            e.has_type = ty
+          case AnyType():
+            new_env = {x:t for (x,t) in env.items()}
+            for p in new_params:
+                new_env[p] = AnyType()
+            e.has_type = FunctionType([AnyType() for _ in new_params], AnyType())
+          case _:
+            raise Exception('lambda does not have type ' + str(ty))
+      case _:
+        e_ty = self.type_check_exp(e, env)
+        self.check_consistent(e_ty, ty, e)
+\end{lstlisting}
+\end{tcolorbox}
+\caption{Type checker for the \LangGrad{} language, part 2.}
+\label{fig:type-check-Lgradual-2}
+\end{figure}
+
+\begin{figure}[tbp]
+\begin{tcolorbox}[colback=white]
+\begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
+  def type_check_stmt(self, s, env, return_type):
+    match s:
+      case Assign([Name(id)], value):
+        value_ty = self.type_check_exp(value, env)
+        if id in env:
+          self.check_consistent(env[id], value_ty, value)
+        else:
+          env[id] = t
+      case Expr(Call(Name('print'), [arg])):
+        arg_ty = self.type_check_exp(arg, env)
+        self.check_type_equal(arg_ty, IntType(), arg)
+      case Expr(value):
+        value_ty = self.type_check_exp(value, env)
+      case If(test, body, orelse):
+        test_ty = self.type_check_exp(test, env)
+        self.check_consistent(BoolType(), test_ty, test)
+        body_ty = self.type_check_stmts(body, env)
+        orelse_ty = self.type_check_stmts(orelse, env)
+        self.check_consistent(body_ty, orelse_ty, ss[0])
+      case FunctionDef(name, params, body, dl, returns, comment):
+        new_env = {x: t for (x,t) in env.items()}
+        for (x,t) in params:
+            new_env[x] = t
+        self.type_check_stmts(body, new_env, returns)
+      case Return(value):
+        self.check_exp(value, return_type, env)
+      case _:
+        raise Exception('type_check_stmts: unexpected ' + repr(ss))
 
+  def type_check_stmts(self, ss, env, return_type):
+    for s in ss:
+      self.type_check_stmt(s, env, return_type)
+\end{lstlisting}
+\end{tcolorbox}
+\caption{Type checker for the \LangGrad{} language, part 3.}
+\label{fig:type-check-Lgradual-3}
+\end{figure}
 
 \begin{figure}[tbp]
 \begin{tcolorbox}[colback=white]  
+\begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
+  def join_types(self, t1, t2):
+      match (t1, t2):
+        case (AnyType(), _):
+          return t2
+        case (_, AnyType()):
+          return t1
+        case (FunctionType(ps1, rt1), FunctionType(ps2, rt2)):
+          return FunctionType([self.join_types(p1, p2) for (p1,p2) in zip(ps1, ps2)],
+                              self.join_types(rt1,rt2))
+        case (TupleType(ts1), TupleType(ts2)):
+          return TupleType([self.join_types(ty1, ty2) for (ty1,ty2) in zip(ts1,ts2)])
+        case (_, _):
+          return t1
+        
+  def check_consistent(self, t1, t2, e):
+    if not self.consistent(t1, t2):
+      raise Exception('error: ' + repr(t1) + ' inconsistent with ' + repr(t2) \
+                      + ' in ' + repr(e))
+
+\end{lstlisting}
+\end{tcolorbox}
+
+\caption{Auxiliary methods for type checking \LangGrad{}.}
+\label{fig:type-check-Lgradual-aux}
+\end{figure}
+
+\fi}
+
+
 {\if\edition\racketEd        
+\begin{figure}[tbp]
+\begin{tcolorbox}[colback=white]  
 \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
 (define type-check-gradual-class
   (class type-check-Llambda-class
@@ -18871,19 +19086,13 @@ print(t[1])
               (values (Prim 'any-vector-set! (list e1^ e2^^ e3^^)) 'Void)]
 	     [else (error 'type-check "expected vector not ~a\nin ~v" t1 e)])]
 \end{lstlisting}
-\fi}
-{\if\edition\pythonEd        
-UNDER CONSTRUCTION
-\fi}
 \end{tcolorbox}
-
 \caption{Type checker for the \LangGrad{} language, part 1.}
 \label{fig:type-check-Lgradual-1}
 \end{figure}
 
 \begin{figure}[tbp]
 \begin{tcolorbox}[colback=white]  
-  {\if\edition\racketEd
 \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
           [(Prim 'eq? (list e1 e2))
            (define-values (e1^ t1) (recur e1))
@@ -18945,20 +19154,13 @@ UNDER CONSTRUCTION
            (define-values (e2^ T2) ((type-check-exp env) e2))
            (values (WhileLoop (make-cast e1^ T1 'Boolean) e2^) 'Void)]
 \end{lstlisting}
-\fi}
-{\if\edition\pythonEd        
-UNDER CONSTRUCTION
-\fi}
 \end{tcolorbox}
-
 \caption{Type checker for the \LangGrad{} language, part 2.}
 \label{fig:type-check-Lgradual-2}
 \end{figure}
 
-
 \begin{figure}[tbp]
-  \begin{tcolorbox}[colback=white]
-{\if\edition\racketEd            
+\begin{tcolorbox}[colback=white]
 \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
 	  [(Apply e1 e2s)
 	   (define-values (e1^ T1) (recur e1))
@@ -18990,20 +19192,13 @@ UNDER CONSTRUCTION
           [else  ((super type-check-exp env) e)]
           )))
 \end{lstlisting}
-\fi}
-{\if\edition\pythonEd        
-UNDER CONSTRUCTION
-\fi}
 \end{tcolorbox}
-
 \caption{Type checker for the \LangGrad{} language, part 3.}
 \label{fig:type-check-Lgradual-3}
 \end{figure}
 
-
 \begin{figure}[tbp]
 \begin{tcolorbox}[colback=white]  
-{\if\edition\racketEd            
 \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
     (define/public (join t1 t2)
       (match* (t1 t2)
@@ -19067,16 +19262,14 @@ UNDER CONSTRUCTION
 	 `(,@ps -> ,rt)]
 	[else (error 'fun-def-type "ill-formed function definition in ~a" d)]))
 \end{lstlisting}
-\fi}
-{\if\edition\pythonEd        
-UNDER CONSTRUCTION
-\fi}
 \end{tcolorbox}
 
 \caption{Auxiliary functions for type checking \LangGrad{}.}
 \label{fig:type-check-Lgradual-aux}
 \end{figure}
 
+\fi}
+
 \clearpage
 
 \section{Interpreting \LangCast{}}