代码之家  ›  专栏  ›  技术社区  ›  Paul Hollingsworth

类型推理中需要“统一”的最简单示例

  •  3
  • Paul Hollingsworth  · 技术社区  · 16 年前

    我试图弄清楚类型推理是如何实现的。 特别是,我不太明白“统一”的重担在哪里/为什么会起作用。

    这样做的天真方式是这样的:

    interface IEnvironment
    {
        object lookup(string name);
    }
    
    interface IExpression
    {
        // Evaluate this program in this environment
        object Evaluate(IEnvironment e);
    }
    

    class Multiply : IExpression
    {
        IExpression lhs;
        IExpression rhs;
        // etc.
        public object Evaluate(IEnvironment e)
        {
            // assume for the moment C# has polymorphic multiplication
            return lhs.Evaluate(e) * rhs.Evaluate(e);
        }
    }
    

    然后,为了“实现”类型推理,你可以做以下事情:

    interface ITypeEnvironment
    {
        Type getType(string name);
    }
    
    interface IExpression
    {
        //as before
        object Evaluate(IEnvironment e);
        // infer type
        Type inferType(ITypeEnvironment typeEnvironment);
    }
    

    class Multiply : IExpression
    {
        IExpression lhs;
        IExpression rhs;
    
        // ... 
        public Type inferType(ITypeEnvironment typeEnvironment)
        {
            Type lhsType = lhs.inferType(typeEnvironment);
            Type rhsType = rhs.inferType(typeEnvironment);
            if(lhsType != rhsType)
                 throw new Exception("lhs and rhs types do not match");
    
            // you could also check here that lhs/rhs are one of double/int/float etc.
            return lhsType;
        }
    }
    

    class Constant : IExpression
    {
        object value;
        public Type inferType(ITypeEnvironment typeEnvironment)
        {
            return value.GetType(); // The type of the value;
        }
        public object Evaluate(IEnvironment environment)
        {
            return value;
        }
    }
    
    class Variable : IExpression
    {
        string name;
        public Type inferType(ITypeEnvironment typeEnvironment)
        {
            return typeEnvironment.getType(name);
        }
        public object Evaluate(IEnvironment environment)
        {
            return environment.lookup(name);
        }
    }
    

    但在这方面,我们最终都不需要“统一”算法。

    什么是最简单的例子,实际上需要“统一”来正确推断表达式的类型。

    3 回复  |  直到 16 年前
        1
  •  2
  •   newacct    16 年前

    让我完全忽略你的例子,给你一个在C#中进行方法类型推理的例子。(如果你对这个话题感兴趣,那么我鼓励你阅读“ type inference “我博客的存档。)

    void M<T>(IDictionary<string, List<T>> x) {}
    

    这里我们有一个泛型方法M,它接受一个将字符串映射到T列表上的字典。假设你有一个变量:

    var d = new Dictionary<string, List<int>>() { ...initializers here... };
    M(d);
    

    我们打过电话 M<T> 而不提供类型参数,因此编译器必须推断它。

    编译器通过“统一”来实现这一点 Dictionary<string, List<int>> 随着 IDictionary<string, List<T>>

    首先,它决定了 Dictionary<K, V> 实现 IDictionary<K, V> .

    由此我们推断 词典<字符串,列表<int>> 实现 IDictionary<string, List<int>> .

    现在我们有一场比赛 IDictionary

    然后我们将List与List统一起来,并意识到我们必须再次递归。

    然后我们将int与T统一,并意识到int是T上的一个界。

    类型推理算法缓慢地运行,直到它无法再取得任何进展,然后它开始从其推理中进行进一步的推断。T的唯一界限是int,因此我们推断调用者一定希望T是int M<int> .

        2
  •  5
  •   Benjol    16 年前
    public Type inferType(ITypeEnvironment typeEnvironment)
    {
        return typeEnvironment.getType(name);
    }
    

    如果你只是不知道变量的类型怎么办?这就是类型推理的全部意义,对吧?一些非常简单的东西,比如这样(用一些伪代码语言):

    function foo(x) { return x + 5; }
    

    你不知道的类型 x ,直到你推断出加法,并意识到它必须是一个整数,因为它被加到一个整数上,或者类似的东西。

    如果你有另一个这样的函数:

    function bar(x) { return foo(x); }
    

    你弄不清它的类型 X 直到你弄清楚了类型 foo 等等。

    因此,当你第一次看到一个变量时,你只需为变量分配一些占位符类型,然后,当该变量传递给某种函数或其他东西时,你必须将其与函数的参数类型“统一”。

        3
  •  2
  •   Larry Watanabe    16 年前

    假设我们有一个函数

    f(x,y)

    或者它可能是FunctionOfInteger。

    假设我们进去

    现在有了统一,u绑定到1,z绑定到2,所以第一个参数是FunctionOfTwoFunctionsOfInteger。

    我对C#不太熟悉,但对于lambda表达式(或等效的委托或其他任何东西),这可能是可能的。

    关于类型推理在提高定理证明速度方面非常有用的一个例子,请看“舒伯特的蒸汽机”

    http://www.rpi.edu/~brings/PAI/schub.steam/node1.html

    《自动推理杂志》上有一期专门讨论这个问题的解决方案和公式,其中大部分涉及定理证明系统中的类型推理:

    http://www.springerlink.com/content/k1425x112w6671g0/

    推荐文章