in f `+` は int -> int -> int => x: int `x + 1` より fun x -> x + 1: int -> int `fun x -> x + 1` よりこの式全体の型は f: int -> int 型に関する連立方程式としてみれる = 型の仮定を置き換えていく = 連立方程式を解く型代入 S をさがす!
Term {} case class Lam(x: String, e: Term) extends Term {} case class App(f: Term, e: Term) extends Term {} case class Let(x: String, e: Term, f: Term) extends Term {}
Term {} 型変数 case class Lam(x: String, e: Term) extends Term {} case class App(f: Term, e: Term) extends Term {} case class Let(x: String, e: Term, f: Term) extends Term {}
Term {} case class Lam(x: String, e: Term) extends Term {} ラムダ式 case class App(f: Term, e: Term) extends Term {} case class Let(x: String, e: Term, f: Term) extends Term {}
Term {} case class Lam(x: String, e: Term) extends Term {} case class App(f: Term, e: Term) extends Term {} 関数適用 case class Let(x: String, e: Term, f: Term) extends Term {}
Term {} case class Lam(x: String, e: Term) extends Term {} case class App(f: Term, e: Term) extends Term {} case class Let(x: String, e: Term, f: Term) extends Term {} let 式
Subst): Subst = { e match { case Var(x) => // 型変数の場合 val u = lookup(env, x) unifier(u.newInstance, t, s) case Lam(x, e1) => // ラムダ式 val a, b = newTyvar() val s1 = unifier(t, Arrow(a, b), s) val env1 = {x, TypeScheme(List(), a)} :: env tp(env1, e1, b, s1) } case App(e1, e2) => // 関数適用 val a = newTyvar() val s1 = tp(env, e1, Arrow(a, t), s) tp(env, e2, a, s1) case Let(x, e1, e2) => // let 式 val a = newTyvar() val s1 = tp(env, e1, a, s) tp({x, gen(env, s1(a))} :: env, e2, t, s1)
Subst): Subst = { e match { case Var(x) => // 型変数の場合 val u = lookup(env, x) unifier(u.newInstance, t, s) case Lam(x, e1) => // ラムダ式 val a, b = newTyvar() val s1 = unifier(t, Arrow(a, b), s) val env1 = {x, TypeScheme(List(), a)} :: env tp(env1, e1, b, s1) } case App(e1, e2) => // 関数適用 val a = newTyvar() val s1 = tp(env, e1, Arrow(a, t), s) tp(env, e2, a, s1) case Let(x, e1, e2) => // let 式 val a = newTyvar() val s1 = tp(env, e1, a, s) tp({x, gen(env, s1(a))} :: env, e2, t, s1) 式の AST を手繰る
Subst): Subst = { e match { case Var(x) => // 型変数の場合 val u = lookup(env, x) unifier(u.newInstance, t, s) case Lam(x, e1) => // ラムダ式 val a, b = newTyvar() val s1 = unifier(t, Arrow(a, b), s) val env1 = {x, TypeScheme(List(), a)} :: env tp(env1, e1, b, s1) } case App(e1, e2) => // 関数適用 val a = newTyvar() val s1 = tp(env, e1, Arrow(a, t), s) tp(env, e2, a, s1) case Let(x, e1, e2) => // let 式 val a = newTyvar() val s1 = tp(env, e1, a, s) tp({x, gen(env, s1(a))} :: env, e2, t, s1) 再帰的な項の探索
Subst): Subst = { e match { case Var(x) => // 型変数の場合 val u = lookup(env, x) unifier(u.newInstance, t, s) case Lam(x, e1) => // ラムダ式 val a, b = newTyvar() val s1 = unifier(t, Arrow(a, b), s) val env1 = {x, TypeScheme(List(), a)} :: env tp(env1, e1, b, s1) } case App(e1, e2) => // 関数適用 val a = newTyvar() val s1 = tp(env, e1, Arrow(a, t), s) tp(env, e2, a, s1) case Let(x, e1, e2) => // let 式 val a = newTyvar() val s1 = tp(env, e1, a, s) tp({x, gen(env, s1(a))} :: env, e2, t, s1) 単一化 再帰的な項の探索
= (s(t), s(u)) match { case (Tyvar(a), Tyvar(b)) if (a == b) => s case (Tyvar(a), _) if !(tyvars(u) contains a) => s.extend(Tyvar(a), u) case (_, Tyvar(a)) => unifier(u, t, s) } case (Arrow(t1, t2), Arrow(u1, u2)) => unifier(t1, u1, unifier(t2, u2, s)) case (Tycon(k1, ts), Tycon(k2, us)) if (k1 == k2) => (ts zip us).foldLeft(s)((s, tu) => unifier(tu._1, tu._2, s)) case _ => throw new TypeError 型代入 S の元で型変数 t と u が同じになるような より拡張した型代入 S’ を探す = 単一化
= (s(t), s(u)) match { case (Tyvar(a), Tyvar(b)) if (a == b) => s case (Tyvar(a), _) if !(tyvars(u) contains a) => s.extend(Tyvar(a), u) case (_, Tyvar(a)) => unifier(u, t, s) } case (Arrow(t1, t2), Arrow(u1, u2)) => unifier(t1, u1, unifier(t2, u2, s)) case (Tycon(k1, ts), Tycon(k2, us)) if (k1 == k2) => (ts zip us).foldLeft(s)((s, tu) => unifier(tu._1, tu._2, s)) case _ => throw new TypeError 同じ型変数ならなにもしない
= (s(t), s(u)) match { case (Tyvar(a), Tyvar(b)) if (a == b) => s case (Tyvar(a), _) if !(tyvars(u) contains a) => s.extend(Tyvar(a), u) case (_, Tyvar(a)) => unifier(u, t, s) } case (Arrow(t1, t2), Arrow(u1, u2)) => unifier(t1, u1, unifier(t2, u2, s)) case (Tycon(k1, ts), Tycon(k2, us)) if (k1 == k2) => (ts zip us).foldLeft(s)((s, tu) => unifier(tu._1, tu._2, s)) case _ => throw new TypeError 片方が型変数のときそれを相手の型での置き換えるように 型環境を拡張する
= (s(t), s(u)) match { case (Tyvar(a), Tyvar(b)) if (a == b) => s case (Tyvar(a), _) if !(tyvars(u) contains a) => s.extend(Tyvar(a), u) case (_, Tyvar(a)) => unifier(u, t, s) } case (Arrow(t1, t2), Arrow(u1, u2)) => unifier(t1, u1, unifier(t2, u2, s)) case (Tycon(k1, ts), Tycon(k2, us)) if (k1 == k2) => (ts zip us).foldLeft(s)((s, tu) => unifier(tu._1, tu._2, s)) case _ => throw new TypeError 関数適用ならそれぞれの引数と返り値が同じになるように 型代入を拡張する
= (s(t), s(u)) match { case (Tyvar(a), Tyvar(b)) if (a == b) => s case (Tyvar(a), _) if !(tyvars(u) contains a) => s.extend(Tyvar(a), u) case (_, Tyvar(a)) => unifier(u, t, s) } case (Arrow(t1, t2), Arrow(u1, u2)) => unifier(t1, u1, unifier(t2, u2, s)) case (Tycon(k1, ts), Tycon(k2, us)) if (k1 == k2) => (ts zip us).foldLeft(s)((s, tu) => unifier(tu._1, tu._2, s)) case _ => throw new TypeError 型コンストラクタならそれぞれの要素の型が同一になるよう 型環境を拡張
Subst): Subst = { e match { case Var(x) => // 型変数の場合 val u = lookup(env, x) unifier(u.newInstance, t, s) case Lam(x, e1) => // ラムダ式 val a, b = newTyvar() val s1 = unifier(t, Arrow(a, b), s) val env1 = {x, TypeScheme(List(), a)} :: env tp(env1, e1, b, s1) } case App(e1, e2) => // 関数適用 val a = newTyvar() val s1 = tp(env, e1, Arrow(a, t), s) tp(env, e2, a, s1) case Let(x, e1, e2) => // let 式 val a = newTyvar() val s1 = tp(env, e1, a, s) tp({x, gen(env, s1(a))} :: env, e2, t, s1) 単一化 再帰的な項の探索
Subst): Subst = { e match { case Var(x) => // 型変数の場合 val u = lookup(env, x) unifier(u.newInstance, t, s) case Lam(x, e1) => // ラムダ式 val a, b = newTyvar() val s1 = unifier(t, Arrow(a, b), s) val env1 = {x, TypeScheme(List(), a)} :: env tp(env1, e1, b, s1) } case App(e1, e2) => // 関数適用 val a = newTyvar() val s1 = tp(env, e1, Arrow(a, t), s) tp(env, e2, a, s1) case Let(x, e1, e2) => // let 式 val a = newTyvar() val s1 = tp(env, e1, a, s) tp({x, gen(env, s1(a))} :: env, e2, t, s1) 項を手繰りながら 連立方程式を立てつつ => 単一化で再帰的に解く
Subst): Subst = { e match { case Var(x) => // 型変数の場合 val u = lookup(env, x) unifier(u.newInstance, t, s) case Lam(x, e1) => // ラムダ式 val a, b = newTyvar() val s1 = unifier(t, Arrow(a, b), s) val env1 = {x, TypeScheme(List(), a)} :: env tp(env1, e1, b, s1) } case App(e1, e2) => // 関数適用 val a = newTyvar() val s1 = tp(env, e1, Arrow(a, t), s) tp(env, e2, a, s1) case Let(x, e1, e2) => // let 式 val a = newTyvar() val s1 = tp(env, e1, a, s) tp({x, gen(env, s1(a))} :: env, e2, t, s1) 型スキームのインスタンス化
Subst): Subst = { e match { case Var(x) => // 型変数の場合 val u = lookup(env, x) unifier(u.newInstance, t, s) case Lam(x, e1) => // ラムダ式 val a, b = newTyvar() val s1 = unifier(t, Arrow(a, b), s) val env1 = {x, TypeScheme(List(), a)} :: env tp(env1, e1, b, s1) } case App(e1, e2) => // 関数適用 val a = newTyvar() val s1 = tp(env, e1, Arrow(a, t), s) tp(env, e2, a, s1) case Let(x, e1, e2) => // let 式 val a = newTyvar() val s1 = tp(env, e1, a, s) tp({x, gen(env, s1(a))} :: env, e2, t, s1) newInstance は全称量化された型変数を ある型変数に固定したコピーを作ってからから単一化する