Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

言語処理系入門€7

818 views

Published on

会社でやっていたソフトウェア基礎講座での講義資料

Published in: Software
  • My struggles with my dissertation were long gone since the day I contacted Emily for my dissertation help. Great assistance by guys from ⇒⇒⇒WRITE-MY-PAPER.net ⇐⇐⇐
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

言語処理系入門€7

  1. 1. 言語処理系入門 第 7 回:型検査,型推論,多相型 2009 年 12 月 11 日(金) 服部 健太
  2. 2. 型検査の目的  プログラムを実行する前にエラーを発見する  例:  let x = 3 + y // 未定義変数の参照  true * “foo” + 2 // 想定していない値同士の演算  3 (false) // 関数でないオブジェクトに対する適用)  { l = “bar”; m = 100 }.n // 未定義フィールド参照  ・・・  プログラムのすべての文面を検査するので,実行(テス ト)しなくてもエラーを発見することができる  プログラムのエラーを早めに発見できる  バグ修正のコスト  後工程になるほど,コストが増大する 2009/12/10 2言語処理系入門 7
  3. 3. 型検査のタイミング  通常は,構文解析が終わった後に,型検査を 行う.(意味解析と呼ぶこともある)  型検査をパスしたプログラムのみ実際に評価 (実行)される  コンパイラの場合は,目的コードに変換される ソース プログラム 字句・構文解析 型検査 評価(実行) 結果 eval_exprcheck_typeparse 2009/12/10 3言語処理系入門 7
  4. 4. 型検査の有効範囲  すべてのエラーを事前に検出できるわけではない  例:スタックオーバフロー,メモリ不足,ゼロ除算,停止 するかどうか, etc. は,実行してみないと検出できない すべての(文法に合致する)プログラム 実行時エラーにならないプログラム 意味的に正しいプログラム 型検査にパスするプログラム 2009/12/10 4言語処理系入門 7
  5. 5. 型検査の基本  抽象構文木をたどりながら,部分式の型を決定して いく.  途中で型規則に違反した式を発見したら,型エラーを報告 する  変数の型は型環境に記録しておく  例: let x = 0 in if x + 3 then x := x + 1 else x == x x LetExpr decl 0 IfExpr AsgnExpr+ x 3 == x xx + x 1 {x→Int} Int Int Int Int Int Int Int Int BoolInt IntInt 条件式がなんであろうとも then 節と else 節をチェッ クすることに注意 ( cf.eval_expr ) 2009/12/10 5言語処理系入門 7
  6. 6. 型アノテーション  関数の型検査をどうする?  let f x = x * x  変数 x の型は何か?  関数の引数の型をプログラマが明示的に示してやる  let f (x:Int) = x * x  式の構文の拡張  E ::= let x:T = E  | fn x:T = E  型式の構文  T ::= Int | Bool | Unit | String  | T → T 2009/12/10 6言語処理系入門 7
  7. 7. 型規則  型判定  「型環境 Γ のもとで,式 E は型 T を持つ」という 関係を Γ|-E:T と表す Tx Tx :| : −Γ Γ∈   2211 22111 ::| :|}{:| TEETx TETxTE inlet =−Γ −Γ−Γ  TEEE TETEBoolE :| :|:|:| 321 321 elsethenif−Γ −Γ−Γ−Γ 211 21 ::| :|}{ TTETx TETx →>−Γ −Γ -fn  ':| :|':| 21 21 TEE TETTE −Γ −Γ→−Γ 2009/12/10 7言語処理系入門 7
  8. 8. 型判定の実装  型の定義( type.ml ) type t = Unit | Bool | Int | String | Fun t * t  型チェック( typing.ml ) let rec check_expr tenv e = match e with ValExpr(ConstVal c) -> Type.of_const c | ValExpr(FunVal(x,texp,e’)) -> let t = Type.of_texp texp in let t’ = check_expr (Env.extend tenv [x,t]) e’ in Type.Fun(t,t’) | VarExpr x -> Env.lookup tenv x | IfExpr(e1,e2,e3) -> let t1 = check_expr tenv e1 and t2 = check_expr tenv e2 and t3 = check_expr tenv e3 in type_equal Type.Bool t1; type_equal t2 t3; t2 | AppExpr(e1,e2) -> let t1 = check_expr tenv e1 and t2 = check_expr tenv e2 in let t,t’ = Type.get_funtyp(t1) in Type.equal t t2; t’ eval_expr と構造 がよく似ている 2009/12/10 8言語処理系入門 7
  9. 9. レコード型,データ(タグ)型の 拡張  type 構文による型名の定義  <type_def> ::= type IDENT = <texp> and …  レコード型,データ型の型式  <texp> ::= { <field>+; } | <tag>+|  <field> ::= LABEL : <texp>  <tag> ::= TAG | TAG of <texp>  例: type person = { name:String; age:Int }; type list = @Nil | @Cons of cell and cell = { car:Int; cdr:list } let make_person n:String a:Int = { name = n; age = a }; let get_name p:person = p.name; let cons a:Int b:list = @Cons{ car = a; cdr = b}; let rec is_nil l:list = case l of @Nil -> true | @Cons _ -> false 2009/12/10 9言語処理系入門 7
  10. 10. 型規則の拡張  レコード型  データ型 }:{:}{| eachfor:| ..1..1 ni ii ni ii ii TlEl iTE ∈∈ =−Γ −Γ jj ni ii TlE TlE :.| }:{:| 1 ..1 1 −Γ −Γ ∈ ><−Γ −Γ ∈ ni iijj jj TlEl TE ..1 ::| :| @ TExlE iTETx TlE ni ii ii ni ii :| eachfor:|}{ ::| ..1 1 ..1 1 ∈ ∈ >−−Γ −Γ ><−Γ @ofcase  2009/12/10 10言語処理系入門 7
  11. 11. 型システムの限界  実行時エラーにはならないけど型エラーとしてはじかれてしま う式がいくつか存在する  let x:Int = 10 in  if x >= 0 then x else “minus”  if 式の then 節と else 節で型が異なるが,実行時にエラーにはならな い  if true then “OK” else 3 + true  3+true は型エラーだが,絶対に実行されないので,実行時にエラー になることはない  実行時エラーになるけど,型エラーとしてはじかれない式もい くつか存在する  let f x:Int = x * (f x)  実行時に Stack overflow エラーになるが,型検査はパスする  let divide x y = x / y in divide 10 0  実行時にゼロ除算エラーとなるが,型検査はパスする 2009/12/10 11言語処理系入門 7
  12. 12. 型推論  動機  プログラマがいちいち型を指示してやるのは煩雑である. (特に型がわかりきっている場合)  let x:Int = 0; // x は 0 なんだから Int なのは自明  関数の型を書くのは面倒(特に関数型言語の場合)  let f g:Int->Bool x:Int = g x  f の型は (Int->Bool)->Int->Bool となる.  f を引数に取るような関数の型はさらに複雑に...  利点  型を書かなくて済むのでプログラムがすっきり  動的型付け言語のような柔軟性(多相型を導入した場合) 2009/12/10 12言語処理系入門 7
  13. 13. 型推論のやり方  定数値の型は明らか  let x = 0 and y = true  演算子や式の構造から推定できるものもある  x + 1; // x の型は Int  if y then “OK” else “NG”; // y の型は Bool)  型がその場でわからないものは後で決められるように場所だけ 用意してやる  型変数の追加 (type.ml)  type t = … | Tyvar of t option ref  Tyvar の中身はとりあえず None を設定し,型 t と同じことがわ かったら Some t に置き換える  型 x が型 y に等しいことがわかった時点で,それらの型を統合 する( unification )  統合に失敗したら型エラー 2009/12/10 13言語処理系入門 7
  14. 14. 型推論の実装(1) let rec check_expr tenv e = match e with ValExpr   v -> check_value tenv v | VarExpr x -> Env.lookup tenv x | IfExpr(e1,e2,e3) -> let t1 = check_expr tenv e1 and t2 = check_expr tenv e2 and t3 = check_expr tenv e3 in unify Type.Bool t1; unify t2 t3; t2 | AppExpr(e1,e2) -> let t = fresh_tyvar() in let t1 = check_expr tenv e1 and t2 = check_expr tenv e2 in unify t1 Type.Fun(t2,t); t 2009/12/10 14言語処理系入門 7
  15. 15. 型推論の実装(2) let fresh_tyvar() = Tyvar(ref None) let rec unify t1 t2 = match t1,t2 with | t1’,t2’ when t1’ == t2’ -> () | Fun(t1’,t1’’),Fun(t2’,t2’’) -> unify t1’ t2’; unify t1’’ t2’’ | Tyvar(topt_ref),t’ | t’,Tyvar(topt_ref) -> unify_tyvar topt_ref t’ | _ -> raise Type_mismatch_error and unify_tyvar tv t = match !tv with | None -> tv := Some t | Some t’ -> unify t t’ 2009/12/10 15言語処理系入門 7
  16. 16. 型推論の実行例 fn f -> fn x -> f (x + 1) (x == 0);  f : tf , x:tx とする  tx = int  t = tf→t1  t1 = tx→t2  t2 は関数適用なので :(f(x+1)) (x == 0)  t3 = bool → t4, t2 = t4  t3 も関数適用なので :f (x + 1)  tf = int→t5, t3 = t5  総合すると ,t : (int->(bool->’a)) -> (int -> ‘a) 2009/12/10 16言語処理系入門 7 t t1t2 t3
  17. 17. 多相型  型検査にパスしないけど,実行時エラーにな らないプログラム  以下のようなプログラムも OK としたい let rec length ls = case ls of      @Nil -> 0    | @Cons x -> 1 + (length x.cdr); length (cons 1 (cons 2 nil)); length (cons true nil);  length の型: ∀ a.list a → Int 2009/12/10 17言語処理系入門 7
  18. 18. let 多相  プログラミング言語 ML や Haskell などの型 システムの基礎  型推論で導入する多相型を let 式に限定する  let x = E1 in E2 式において, x が多相型になりうる  let f x y = x y のように関数の引数としての変数は単相型  全称記号∀は常に一番外側にのみ現れる  多相型の型推論が可能になる 2009/12/10 18言語処理系入門 7
  19. 19. let 多相の実装  let x=E1 in E2 の型推論で, E1 の型が T1 と推論さ れたとする  T1 に現れる自由な型変数を多相型に一般化し,型環 境に {x→Gen(T1)} を追加  ∀t1…tn.T1 where {t1,…tn} = FTV(T1)/FTV(Γ)  自由な型変数に限る理由 : (fn f x -> let g = f in g 0) (fn x -> if x then true else false) true  g に∀ a.a→a という多相型を与えると,型検査をパスしてし まう  E2 の中に x が出現したら,その都度,多相型を具体 化した型をその x の型とする  ∀t1…tn.T1 の場合,フレッシュな型変数 u1,…,un を生成し, T1 の t1,…tn をそれぞれ, u1,…,un で置き換える. 2009/12/10 19言語処理系入門 7
  20. 20. 多相型の制限  副作用を許す言語だと,不用意に多相型を導入すると,不健全 な型システムになる  不健全な型システムとは,実行時型エラーになるプログラムが 型検査をパスしてしまうような型システム  健全な型システムでは型検査をパスしたら,そのプログラムは絶対 に実行時型エラーにならないことが保証される  例: let f = fn x -> x in // f : a.a->a∀ begin f := fn x -> x + 1; // 型検査をパス (f true) // 実行時型エラー発生 end  解決策  代入を許す ref 型を導入し, ref 型の場合は多相型を与えない 2009/12/10 20言語処理系入門 7
  21. 21. let 多相の限界  例:  let make_pair f x y = {fst=f x; snd=f y};  上記の関数の型は以下のように推論される  ∀a b. (a→b)→a→a→pair b b  make_pair (fn x->x) 3 true; は問題なく実行できるのに型エラー となる  引数 f に多相型を許すと,期待する make_pair の型は一意に推 論できない  ∀a b.( c.c→c)→a→b→pair a b∀  ∀a b.( c.c→list c)→a→b→pair (list a) (list b)∀  …  let 多相の制限を緩和する型システムは現在でもいろいろと研究 されている  S.P.Jones, et.al, “Practical type inference for arbitrary-rank types”, J.Func.Prog., 2007. 2009/12/10 21言語処理系入門 7
  22. 22. 参考文献  B.C.Pierce, “Types and Programming Languages”, MIT Press, 2002.  通称 TAPL .これ一冊読めば基本的なことは大体わかる.  http://www.amazon.co.jp/Types-Programming-Languages- Benjamin-Pierce/dp/0262162091 2009/12/10 22言語処理系入門 7
  23. 23. 進んだ話題  制御オペレータの型付け  O.Danvy&A.Filinsky,”A Functional Abstraction of Typed Contexts”, DIKU,TechRep 1989. B.F.Duba,et.al,”Typing First-Class Continuations in ML”, POPL 91.  K.Asai&Y.Kameyama,”Polymorphic Delimited Continuations”, APLAS 2007.  多相型の拡張  A.Ohori, “A Polymorphic Record Calculus and Its Compilation”, TOPLAS 1995.  M.Odersky&K.Laufer, “Putting Type Annotations to Work”, POPL 1997.  D.Leijen, “HMF:Simple type inference for first-class polymorphism”, ICFP 2008. 2009/12/10 23言語処理系入門 7
  24. 24. 演習問題  今週のサンプルプログラムを動かしてみよ 2009/12/10 24言語処理系入門 7
  25. 25. 次回予定  日時:  2009 年 12 月 18 日(金) 10 : 30 - 12 : 00  場所:  LB2 3F/A  内容:  コンパイル I : CPS 変換 2009/12/10 25言語処理系入門 7

×