Arantium Maestum

プログラミング、囲碁、読書の話題

2022-10-01から1ヶ月間の記事一覧

型推論を実装・改善していく6.5 組み込み関数の多相型推論

このようなツイートを拝見した: instantiationだけ実装すれば組み込み関数の多相化が出来るのでは?— taka2 (@Jj1Fxh) October 30, 2022 確かにそのとおりで、単相型推論からLet多相の間に「ユーザ定義の関数は単相だが特定の組み込み関数は多相」という型…

型推論を実装・改善していく10 レベルによるLet多相の効率化(後編)

前回に続いてLet多相にレベルを導入した実装の詳細を見ていく。 具体的にはinstantiate、match_fun_ty、unify、occursinがレベルの導入でどう影響を受けるかという点と、unifyで新しく使われるadjustlevelの理屈と実装を解説する。 instantiate 汎化された型…

型推論を実装・改善していく9 レベルによるLet多相の効率化(前編)

前回、前々回と見てきたLet多相はgeneralizeが非常に非効率で、環境に含まれている型すべてを調べる必要があった。 初期のML(少なくとも初期のCAML)ではこのような実装になっており、その頃の遅いコンピュータ上でも殊更HM型推論が遅いことが認識されていた…

型推論を実装・改善していく8 Let多相型推論(後編)

前回に続いてLet多相の実装を見ていく。 generalize 前回書いたとおり、generalizeはLet式で「変数の型」を汎化する: let rec typeof env = function ... | ELet(svar, e, ebody) -> let tvar = typeof env e in let tgen = generalize (List.map snd env) …

型推論を実装・改善していく7 Let多相型推論(前編)

今回からHindley Milner型推論の要であるLet多相を実装していく。 これまで見てきた型推論は単相な関数しか扱えなかった。例えばこのようなコードはOCamlでは通る: utop # let id x = x = x in id 1 && id "hello";; - : bool = true しかし単相的な型推論…

型推論を実装・改善していく6 ミュータブルな型変数を使った単相型推論(後編)

前回に続いてミュータブルな型変数に対する破壊的代入で実装する効率的な単相型推論について見ていく。今回はtypeof関数の内部で使われているmatch_fun_ty、そしてunify, occursinの実装について。 match_fun_ty 前回見たとおり、型推論・型検査を行うtypeof…

型推論を実装・改善していく5 ミュータブルな型変数を使った単相型推論(前編)

「型推論を実装・改善していく3 純粋関数型な単相型推論(後編)」で書いたとおり、型推論のTaPL実装は副作用を使わない純粋関数型なもので、型制約のリストを正しく変換するunify関数がリストの長さnに対してO(n**2)な処理になっている。 その非効率さを改…

型推論を実装・改善していく4 状態を持つ型変数生成

前回書いた通り、TaPL準拠の型推論が完全に純粋関数型なのに対して、「ユニークな型変数を作る」new_tvar関数に状態を持たせることでいちいち引数・返り値のタプルの一部として渡し回さなくてもいいようにする。 HaskellだったらStateモナドの出番なのだろう…

型推論を実装・改善していく3 純粋関数型な単相型推論(後編)

前々回、前回に続いて純粋関数型な単相型推論の実装を詳細に見ていく。コードの全容はこちら。 型推論・型検査の関数であるtypeof: let typeof env new_tvar constr e = let (t, new_tvar, constr1) = infer env new_tvar e in let constr = unify (constr …

型推論を実装・改善していく2 純粋関数型な単相型推論(中編)

前回に続いて純粋関数型な単相型推論の実装を詳細に見ていく。コードの全容はこちら。 具体的には前回見たtypeof関数: let typeof env new_tvar constr e = let (t, new_tvar, constr1) = infer env new_tvar e in let constr = unify (constr @ constr1) i…

型推論を実装・改善していく1 純粋関数型な単相型推論(前編)

型推論がある型システムを実装した上で改善していく。 具体的には TaPLのType Reconstruction準拠の単相な型推論を純粋関数型な単一化で実装 型変数の作成と単一化を破壊的代入で行うようにする(効率化) 型推論をLet多相に拡張 型変数を汎化していいかの確…

簡単な型システムを実装していく15 STLC+...+Error (6)

typeof関数のRefとError関連のケースを部分型に対応させる。今回でエラーに関する話は最後。 Ref 以前書いたとおり、安易にRefにBottomを含む型を持たせると型安全性が破壊されてしまう。なのでRefに入る値の型にはBottomがまったくないという厳しめの制約を…

簡単な型システムを実装していく14 STLC+...+Error (5)

今回はtypeof関数がレコード、バリアント、Fix関連でどう部分型に対応していくかを見ていく。 レコード レコードはフィールドの値が一つでもBottom型だったら全体がBottom型になる: | ERecord les -> let lts = (List.map (fun (l,e)->(l, typeof env e)) l…

簡単な型システムを実装していく13 STLC+...+Error (4)

今回はtypeof関数がSTLCのVar, Abs, AppそしてBool, Nat, Let関連でどう部分型に対応していくかを見ていく。 まずは変わらない部分から。 EVar, EAbs, ETrue, EFalse, ENat, ELetは変わらない: let rec typeof env = function | EVar var -> List.assoc var…

簡単な型システムを実装していく12 STLC+...+Error (3)

前回に続いて、エラー処理のある言語を型検査できる型システムを実装する話。今回は部分型全般やBottom型に対するチェックを行うヘルパ関数について。 導入するヘルパ関数は四つ: ある型がある型の部分型かどうかを調べるis_subtype 部分型関係を考慮に入れ…

Goのforループの変数スコープについてのメモ

以前Pythonのfor-loopでの変数スコープについてちょこっと書いた。 zehnpaard.hatenablog.com 最近Go言語でも似たような(?)問題があることを知ったので備忘録として残しておく。ちなみに私はGo言語は資料を少し読んだことはあるが書いたことはないので正…

簡単な型システムを実装していく11 STLC+...+Error (2)

前回書いたとおり、エラー式の型であるBottom型が部分型として正しく振る舞えるような変更を加えていく必要がある。 Bottom型に関して注意しておくべき最大のポイントは以下の二つ: Bottom型はすべての型の部分型である。ということはBottom型の式は他のど…

簡単な型システムを実装していく10 STLC+...+Error (1)

例外を投げるようなエラー処理のための型システムを追加していく。 今までの変更に比べて圧倒的に複雑なので複数回にわけている。 何が複雑かというと、「エラーが投げられた箇所の式の型は何か?」という問題の答えが「任意の型を取り得る」というものだか…

簡単な型システムを実装していく9 STLC+...+Variant+Fix+Ref

MLの一つの特徴として、デフォルトではほとんどの変数やデータ構造に破壊的代入が不可だが、破壊的代入が可能なデータ構造を明示的に選択することが可能、という非純粋な関数型プログラミング言語であることが挙げられる。そういった非純粋性を支える一つの…

簡単な型システムを実装していく8 STLC+...+Variant+Fix

再帰関数を定義できるようにするために不動点オペレータFixを追加する。型のないラムダ計算だと普通のラムダ抽象として定義できるのだが、STLCでは型をつけることができないので組み込みのオペレータとして用意する必要がある。 TaPLからの例を取ると: ff =…

簡単な型システムを実装していく7 STLC+Bool+Nat+Let+Record+Variant

型システムにバリアント型とケースに対するパターンマッチを追加する。 こういうやつ: type t = Name of string | Id of int let to_str = function Name s -> s | Id n -> string_of_int n 代数的データ型における直和型であり、前回の直積型と合わせると…

簡単な型システムを実装していく6 STLC+Bool+Nat+Let+Record

前回のLetまで実装した型システムにレコードを追加する。 gist.github.com レコードというのは{x=1; y=true}のような値にラベルのついたデータ構造。ちなみにタプルは型システム的にはレコードの亜種と考えていい(ラベルが0~の整数だと見做せる)。どちらも…

簡単な型システムを実装していく5 STLC+Bool+Nat+Let

前回のコードにLetによる変数束縛を追加する。 gist.github.com コードの追加としては2行のみと非常に短い。 型 変更なし 式 追加するのはLetだけ: type exp = ... | ELet of string * exp * exp ELet(変数、変数を束縛する式、本体の式)という構成になっ…

簡単な型システムを実装していく4 STLC + Bool + Nat

前回のSTLC+Boolに自然数と関連する機能を追加していく。 gist.github.com 型 TNatという自然数を表す型を追加: type ty = ... | TNat 式 三種類の式を追加: type exp = ... | ENat of int | EAdd of exp * exp | EIsZero of exp 自然数リテラルを表すENat…

簡単な型システムを実装していく3 STLC + Bool

前回のSTLCにBool型と関連する式を追加してみる: gist.github.com まずは型にTBoolを追加: type ty = ... | TBool 式にTrue, FalseとIf式を追加: type exp = ... | ETrue | EFalse | EIf of exp * exp * exp If式はcondition式、if-true-branch式、if-fal…

簡単な型システムを実装していく2 STLC

前回Simple Boolからはじめると書いたのだが、よく考えると単純型付きラムダ計算(STLC)ではじめるのが当然な筋な気がしてきた。 ので急遽Simple BoolからBoolを取っ払ってSTLCだけをまずみてみる: gist.github.com 定義されるものとしては 「型」を表す型…

簡単な型システムを実装していく1 序文

最近は言語処理系に関してまったく手を動かしていなかった&ブログに何も書いていなかったので練習がてら・・・ Types and Programming Languagesには非常にたくさんの型システムの実例と関連したOCamlコードが載っている。ただし多くは写経したらそのまま実…