Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.

言語処理系入門€7

832 Aufrufe

Veröffentlicht am

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

Veröffentlicht in: Software
  • Login to see the comments

言語処理系入門€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

×