簡體   English   中英

如何使用算法W鍵入檢查遞歸定義?

[英]How to type check recursive definitions using Algorithm W?

我在JavaScript中實現Algorithm WHindley-Milner類型系統 ):

算法W.

實現上述規則的函數是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);
    }
}

關於數據類型的一點點:

  1. 上下文是將標識符映射到多類型的對象。

     type Context = Map String Polytype 
  2. 表達式由以下代數數據類型定義:

     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函數以允許遞歸定義

遞歸定義

哪里:

  1. 遞歸定義上下文之一
  2. 遞歸定義上下文二

但是,我遇到了雞和蛋的問題。 上下文第一個具有假設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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM