Function 如何对没有显式返回类型的递归函数进行类型检查?

Function 如何对没有显式返回类型的递归函数进行类型检查?,function,recursion,compiler-construction,typechecking,function-call,Function,Recursion,Compiler Construction,Typechecking,Function Call,我正在写一种没有键入函数的语言。这意味着我需要推断函数调用的返回类型,以便进行类型检查。然而,当有人编写递归函数时,类型检查器进入无限递归,试图推断函数体中函数调用的类型 类型检查器执行如下操作: 推断函数调用实际参数的类型 创建实际参数类型到形式参数的映射 使用映射对函数体内部使用的参数上的类型进行注释 推断并返回函数体的返回类型 第4步尝试推断函数体中函数调用的类型,该函数体再次调用相同的类型检查器函数,导致无限递归 递归函数的一个例子给了我这个问题: function factorial(

我正在写一种没有键入函数的语言。这意味着我需要推断函数调用的返回类型,以便进行类型检查。然而,当有人编写递归函数时,类型检查器进入无限递归,试图推断函数体中函数调用的类型

类型检查器执行如下操作:

  • 推断函数调用实际参数的类型
  • 创建实际参数类型到形式参数的映射
  • 使用映射对函数体内部使用的参数上的类型进行注释
  • 推断并返回函数体的返回类型
  • 第4步尝试推断函数体中函数调用的类型,该函数体再次调用相同的类型检查器函数,导致无限递归

    递归函数的一个例子给了我这个问题:

    function factorial(n) = n<1 ? 1 : n*factorial(n-1); // Function definition.
    ...
    assert 24 == factorial(4); // Function call expression usage example.
    

    function factorial(n)=n类型推断可能会有很大的变化,这取决于语言的类型系统以及在需要注释时希望具有的属性。但不管你的语言是什么样的,我认为有一个开创性的案例你真的应该读一下,那就是。ML的类型推断有一个很好的最佳点,在这个点上,所有的类型都可以在一个相对简单的范例中组合在一起。不需要类型注释,任何表达式都有一个最通用的类型(此属性称为类型公理)

    ML的类型系统是,它具有。表达式的类型可以是特定类型,也可以是“任意”。更准确地说,表达式的类型构造函数是特定类型构造函数或“any”,类型构造函数可以具有参数,这些参数本身具有特定类型构造函数或“any”。例如,空列表的类型为“任意列表”。两个单独具有“any”类型的表达式可能会被约束为具有相同的类型,不管它是什么,因此“any”用变量表示。例如,
    function list\u of_two(x,y)=[x,y]
    (使用与您的语言类似的表示法)将
    x
    y
    约束为具有相同的类型,因为它们插入到相同的列表中,但该类型可以是任何类型,因此此函数的类型为“取同一类型α的任意两个参数,并返回α类型列表的值”

    Hindley-Milner的基本类型推断算法是。在其核心,它通过给每个子表达式一个变量类型:α来工作₁, α₂, α₃, … 然后,编程语言构造对这些变量施加约束₁ 和α₂ 列表本身的类型是α₃, 这个约束条件是α₁ = α₂ 和α₃ = α列表₁. 把所有这些约束放在一起是一个问题

    这些约束是基于对程序的纯语法读取。如果有递归调用,则不需要知道函数的类型:这只是意味着存在一个约束,即函数返回类型的变量与其使用点的类型相同。这只是要添加到constr集合中的另一个等式不

    我遗漏了ML的一个重要方面,即表达式的类型可以通用化:表达式可以在不同的位置与不同的类型一起使用。这就是允许多态性的原因。例如

    let empty_list = [] in
    (empty_list @ [3]), (empty_list @ ["hello"])
    
    是一个有效的程序,
    empty_list
    一次与类型“整数列表”一起使用,一次与类型“字符串列表”一起使用。
    empty_list
    的类型是“对于任何α,α列表”:这是参数多态性。泛化为算法增加了一些复杂性,但也消除了其他地方的复杂性,因为这是允许公国的原因。没有它,
    let empty_list=[]在…
    中可能会有歧义:
    空列表必须有某种类型,但是如果不分析
    ,就无法知道是什么类型,然后当您分析上面的
    时,您需要在整数和字符串之间做出选择


    根据您语言的类型系统,ML和算法W可能可以直接重用,也可能只是提供一些模糊的启示。但在推理过程中使用变量并逐步约束这些变量的原则非常普遍。

    您必须为函数指定一些占位符类型,然后在需要时填写它信息可用。让我们调用
    factorial
    T
    的类型,然后继续。我们知道
    T
    是一个函数。接下来我们看到函数接受一个参数,所以我们将
    T
    更新为“一个参数的函数”。然后看到在
    n<1
    的情况下,它返回
    1
    。因此
    T
    必须是“一个参数返回整数的函数”。现在我们来看
    n*阶乘(n-1)
    ,我们现在知道,
    n
    正被一个整数相乘,等等。注意,虽然倾向于接受像这样的关于应用计算机科学的边缘问题,但它们更集中在主题上,并且有更好的机会在主题上得到好的答案。不要转发,但如果你喜欢你的问题,你可以标记你的问题,并要求主持人迁移它。这篇文章非常清楚地解释了Hindley-Milner类型的系统,它甚至包括了一个例子。它很好地补充了这个答案。对于任何想用自己的语言实现系统的人来说,这是一个很好的起点。