[英]How to type check recursive definitions using Algorithm W?
我在JavaScript中實現Algorithm W ( Hindley-Milner類型系統 ):
實現上述規則的函數是typecheck
,它具有以下簽名:
typecheck :: (Context, Expr) -> Monotype
它的定義如下:
function typecheck(context, expression) {
switch (expression.type) {
case "Var":
var name = expression.name;
var type = context[name];
return inst(type);
case "App":
var fun = typecheck(context, expression.fun);
var dom = typecheck(context, expression.arg);
var cod = new Variable;
unify(fun, abs(dom, cod));
return cod;
case "Abs":
var param = expression.param;
var env = Object.create(context);
var dom = env[param] = new Variable;
var cod = typecheck(env, expression.result);
return abs(dom, cod);
case "Let":
var assignments = expression.assignments;
var env = Object.create(context);
for (var name in assignments) {
var value = assignments[name];
var type = typecheck(context, value);
env[name] = gen(context, type);
}
return typecheck(env, expression.result);
}
}
關於數據類型的一點點:
上下文是將標識符映射到多類型的對象。
type Context = Map String Polytype
表達式由以下代數數據類型定義:
data Expr = Var { name :: String } | App { fun :: Expr, arg :: Expr } | Abs { param :: String, result :: Expr } | Let { assignments :: Map String Expr, result :: Expr } | Rec { assignments :: Map String Expr, result :: Expr }
此外,我們還具有算法所需的以下功能,但對於該問題並不重要:
inst :: Polytype -> Monotype
abs :: (Monotype, Monotype) -> Monotype
gen :: (Context, Monotype) -> Polytype
inst
函數專門用於polytype, gen
函數概括了一個monotype。
無論如何,我想擴展我的typecheck
函數以允許遞歸定義 :
哪里:
但是,我遇到了雞和蛋的問題。 上下文第一個具有假設v_1 : τ_1, ..., v_n : τ_n
。 此外,它意味着e_1 : τ_1, ..., e_n : τ_n
。 因此,您首先需要創建上下文以查找e_1, ..., e_n
的類型e_1, ..., e_n
但是為了創建上下文,您需要找到e_1, ..., e_n
的類型。
你怎么解決這個問題? 我正在考慮將新的monotype變量分配給標識符v_1, ..., v_n
,然后將每個monotype變量與其各自的類型統一起來。 這是OCaml用於let rec
綁定的方法。 但是,此方法不會產生最常見的類型,如以下OCaml代碼所示:
$ ocaml
OCaml version 4.02.1
# let rec foo x = foo (bar true)
and bar x = x;;
val foo : bool -> 'a = <fun>
val bar : bool -> bool = <fun>
但是,GHC確實計算了最常見的類型:
$ ghci
GHCi, version 7.10.1: http://www.haskell.org/ghc/ :? for help
Prelude> let foo x = foo (bar True); bar x = x
Prelude> :t foo
foo :: Bool -> t
Prelude> :t bar
bar :: t -> t
如您所見,OCaml推斷類型val bar : bool -> bool
而GHC推斷類型bar :: t -> t
。 Haskell如何推斷函數bar
的最常見類型?
我從@augustss的回答中了解到,遞歸多態函數的類型推斷是不可判定的。 例如,如果沒有其他類型注釋,Haskell無法推斷以下size
函數的類型:
data Nested a = Epsilon | Cons a (Nested [a])
size Epsilon = 0
size (Cons _ xs) = 1 + size xs
如果我們指定類型簽名size :: Nested a -> Int
那么Haskell接受該程序。
但是,如果我們只允許代數數據類型的子集, 歸納 類型 ,那么數據定義Nested
變得無效,因為它不是歸納的; 如果我沒有弄錯,那么歸納多態函數的類型推斷確實是可判定的。 如果是這樣,那么用於推斷多態感應函數類型的算法是什么?
你可以使用帶有類型(a -> a) -> a
的原始fix
顯式遞歸來鍵入它。 您可以手動或自動插入修復程序。
如果你想擴展類型推斷,那么這也很容易。 遇到遞歸函數f時,只需生成一個新的統一變量,並在環境中放置此類型的f。 在對主體進行類型檢查后,使用此變量統一主體類型,然后照常進行概括。 我想這就是你的建議。 它不會允許你推斷多態遞歸,但這通常是不可判定的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.