# 部分的型づけそる場 ## 前提 Lit と and / or を含む (intersect と union を表す) S, T = Top | Bottom | T -> T | or (Tn) | and (Tn) | int | num... | 1 | 2 ... | true | false VS, VT = Top | Bottom | VT -> VT | ... | x (型変数) における型づけ。 subtyping の計算は型変数を含まない T でのみできるとする subtyping の計算 or (Tn) Constraint VT <: VT のセットについて解決を試みる。 ## 基本的な考えかた cts : Set [Constraint] を受け取る ### 1. cts の中身を適切に分解し、最大限 x <: VT または VT <: x という形に帰着させる 基本的な分解操作の一覧 - VS <: and (VTn) → n について VS <: VT_n - or (VSn) <: VT → n について VS_n <: VT - (VS1 -> VS2) <: (VT1 -> VT2) → VT1 <: VS1 と VS2 <: VT2 これらを施すと次のような形に帰着する (?) i. 両辺とも T ← 嬉しい! ii. 右辺か左辺が x で、もう片方が VT ← わりと嬉しい! iii. 右辺が or で, 左辺が x でない - VS <: or (VTn) iv. 左辺が and で, 右辺が x でない - and (VSn) <: VT v. 片方の辺が VT の func type で、もう片方の辺が x でも func でも and/or でもない, したがって下のどれかになる - VS1 -> VS2 <: int/num... /0/1 ... - int/num...0/1/... <: VS1 -> VS2 - VS1 -> VS2 <: Top/Bottom - Top/Bottom <: VS1 -> VS2 ### 2. cts 矛盾チェック i の場合は決定的に subtyping のチェックができる (本当に?) v の場合も同様 ii の場合の特殊な場合として、 x <: x があげられる。この場合は矛盾を起こさないので OK! → チェック済みとする これによって矛盾が起きたら cts は矛盾しているものとしてブランチを棄却 これによってチェックしたものは cts から消す ### 3. 境界の計算と境界条件の伝播 前の作業によって ii, iii, iv の場合のみが残っている ここで、ii (つまり片方が x のもの) を使って型境界を計算する 下限と上限を全て集めると次のようになる {下限の型...} <: x <: {上限の型...} なお、iii, iv および (ii の変数でない方)に x がある可能性が残っているので、この下限、上限を満たせば必ず型解決できるわけではない ※iii, iv の場合はダメなのはわかりやすいが ii の場合は次のようなものがある x <: number (1 -> numebr) <: y <: (x -> number) このセットでは、x ~ 1 なら OK だが x ~ number なら矛盾である さて、計算した下限 VS_n, VT_n について、次のような Constraint を新たに cts に追加する or (VS_m) <: and (VT_n) # ここで normalize が効きそう (なお、すでに追加しているもの、自明に矛盾なものはその限りでない) また、x に関係する制約を or (VS_m) <: x と x <: and (VT_n) のみに統一する。 ### 4. 自明な代入と cts の refinement 上限と下限に同じ式が含まれているなら、x に代入する。 1 ~ 4 を変化がなくなるまで繰り返す ### 5. ブランチの分岐 → 分岐できない場合は 7 へ 次のような形の Constraint が残っている ii. 右辺か左辺が x で、もう片方が VT iii. 右辺が or で, 左辺が x でない iv. 左辺が and で, 右辺が x でない ここで ii を二つに分解して考える ii(a). 右辺か左辺が x で、もう片方がTop, Bottom, 変数, 1, 2... , num, int,... のような一回の型 ii(b), 右辺か左辺が x で、もう片方がfunction (なお、and / or は iii, iv および分解で排除される) このうち、iii, iv, ii(b) について、次のように cts を分解する #### ii(b) の場合 cts を cts1 と cts2 にコピーする x <: VS -> VT の場合 x は Bottom か関数型である必要がある。 - cts1 では x に Bottom を代入する - cts2 では新しい変数 y, z に対し x に y -> z を代入する VS -> VT <: x の場合 x は Top か関数型である必要がある - cts1 では x に Top を代入する - cts2 では新しい変数 y, z に対し x に y -> z を代入する もとの Constraint は削除 #### iii の場合 x <: or (VTn) となっている n 個の cts を作成し、それぞれ x <: VTn を制約として追加する もとの Constraint は削除 #### iv の場合 iii と同様 ### 6. 分岐した cts の計算 分岐したそれぞれについて solve し、矛盾がないブランチが見つかったなら矛盾なし、すべて矛盾があった場合、矛盾とする ### 7. 矛盾 / 非矛盾の判定 すでに ii(b) しか残っていない。すなわち Top, Bottom, x, lit, prim 間の制約に帰着している。 4 の制約伝播によって、この時点で矛盾がなければ矛盾がないとしてよい (未証明、要検証、または反例求)  → ChatGPT はサイクルが無ければ問題ないと言っています! でも 4 でサイクル消える気がする y <: x <: y となったとき x <= y と代入されるので ## 補遺 ### Normalize について 各種 and/or を取る操作において、より単純な形に変換した方が良い結果を生む。次のような変換を行う VT | Bottom = VT VT | Top = Top VT | VT = VT VT & Bottom = Bottom VT & Top = VT VT & VT = VT T1 | T2 where T1 <: T2 = T2 (subtyping を計算するので、変数を含まない型のみ) T1 & T2 where T1 <: T2 = T1 分配法則 (or に寄せる) (パフォーマンス悪化の可能性あり?) (逆変換の方が良いか 共通部分見つけるのダルそうだけど) VT1 & (VT2 | VT3) = (VT1 & VT2) | (VT1 & VT3) 関数化 (関数の分解法則が使える可能性が上がる?) (VT1 -> VT2) | (VT3 -> VT4) = (VT1 & VT2 -> VT2 | VT4) (VT1 -> VT2) & (VT3 -> VT4) = (VT1 | VT2 -> VT2 & VT4) 例えば左辺なら | にして右辺なら 関数にする (& も同様) とかいいかも 分解規則をできるだけ使いたい 吸収 VT1 & (VT1 | VT2) = VT1 VT1 | (VT1 & VT2) = VT1 バックエンドは JavaScript で、基本的に (A -> B) | (C -> D) の意味としては 「A -> B または C -> D という関数型入っている」で、ここに型変換はからまないので、この関数に A & B を適用して C | D を得ることは合法。 逆に (A & B) -> (C | D) も (A -> B) | (C -> D) として見ることが出来る (外延的な等価) JavaScript の instanceof などの使用は制限するのでこれらの型は等しくなる ブランチングは特殊。 A <: distinguishable なら、branch : A | B -> (A -> C) -> B | C ができる。