Recursion 数字类型推断

Recursion 数字类型推断,recursion,sml,church-encoding,Recursion,Sml,Church Encoding,我在SML中有这个表达式,需要找到它的最一般类型。当运行编译器时,我得到了下面显示的内容。我怎样才能找到最普遍的类型,不仅是这个函数,还有其他函数,比如教堂数字函数“2” 为什么是这种类型: ('a -> 'b) -> 'a -> 'b 我真的不明白你的问题,所以我只是猜测 如果我在REPL中定义第一个数字函数: val c0 = fn f => fn x => x val c1 = fn f => fn x => f x val c2 = fn f

我在SML中有这个表达式,需要找到它的最一般类型。当运行编译器时,我得到了下面显示的内容。我怎样才能找到最普遍的类型,不仅是这个函数,还有其他函数,比如教堂数字函数“2”

为什么是这种类型:

('a -> 'b) -> 'a -> 'b

我真的不明白你的问题,所以我只是猜测

如果我在REPL中定义第一个数字函数:

val c0 = fn f => fn x => x
val c1 = fn f => fn x => f x
val c2 = fn f => fn x => f (f x)
val c3 = fn f => fn x => f (f (f x))
val c4 = fn f => fn x => f (f (f (f x)))
。。。然后看看它们的类型:

val c0 = fn : 'a -> 'b -> 'b
val c1 = fn : ('a -> 'b) -> 'a -> 'b
val c2 = fn : ('a -> 'a) -> 'a -> 'a
val c3 = fn : ('a -> 'a) -> 'a -> 'a
val c4 = fn : ('a -> 'a) -> 'a -> 'a 
。。。在第二个函数之后出现类型('a->'a)->'a->'a。这是你要找的普通类型吗

前两个函数的类型不同只是因为类型推断算法选择了最通用的类型。对于第一个函数,'a->'b->'b('a->'a)->'a->'a一样,是一个更通用的类型。但您始终可以使用类型注释向编译器提供提示:

val c0 : ('a -> 'a) -> 'a -> 'a = fn f => fn x => x
val c1 : ('a -> 'a) -> 'a -> 'a = fn f => fn x => f x

。。。现在所有函数都应该有相同的类型。

我不太理解你的问题,所以我只是在猜测

如果我在REPL中定义第一个数字函数:

val c0 = fn f => fn x => x
val c1 = fn f => fn x => f x
val c2 = fn f => fn x => f (f x)
val c3 = fn f => fn x => f (f (f x))
val c4 = fn f => fn x => f (f (f (f x)))
。。。然后看看它们的类型:

val c0 = fn : 'a -> 'b -> 'b
val c1 = fn : ('a -> 'b) -> 'a -> 'b
val c2 = fn : ('a -> 'a) -> 'a -> 'a
val c3 = fn : ('a -> 'a) -> 'a -> 'a
val c4 = fn : ('a -> 'a) -> 'a -> 'a 
。。。在第二个函数之后出现类型('a->'a)->'a->'a。这是你要找的普通类型吗

前两个函数的类型不同只是因为类型推断算法选择了最通用的类型。对于第一个函数,'a->'b->'b('a->'a)->'a->'a一样,是一个更通用的类型。但您始终可以使用类型注释向编译器提供提示:

val c0 : ('a -> 'a) -> 'a -> 'a = fn f => fn x => x
val c1 : ('a -> 'a) -> 'a -> 'a = fn f => fn x => f x

。。。现在所有函数都应该有相同的类型。

我不太理解你的问题,所以我只是在猜测

如果我在REPL中定义第一个数字函数:

val c0 = fn f => fn x => x
val c1 = fn f => fn x => f x
val c2 = fn f => fn x => f (f x)
val c3 = fn f => fn x => f (f (f x))
val c4 = fn f => fn x => f (f (f (f x)))
。。。然后看看它们的类型:

val c0 = fn : 'a -> 'b -> 'b
val c1 = fn : ('a -> 'b) -> 'a -> 'b
val c2 = fn : ('a -> 'a) -> 'a -> 'a
val c3 = fn : ('a -> 'a) -> 'a -> 'a
val c4 = fn : ('a -> 'a) -> 'a -> 'a 
。。。在第二个函数之后出现类型('a->'a)->'a->'a。这是你要找的普通类型吗

前两个函数的类型不同只是因为类型推断算法选择了最通用的类型。对于第一个函数,'a->'b->'b('a->'a)->'a->'a一样,是一个更通用的类型。但您始终可以使用类型注释向编译器提供提示:

val c0 : ('a -> 'a) -> 'a -> 'a = fn f => fn x => x
val c1 : ('a -> 'a) -> 'a -> 'a = fn f => fn x => f x

。。。现在所有函数都应该有相同的类型。

我不太理解你的问题,所以我只是在猜测

如果我在REPL中定义第一个数字函数:

val c0 = fn f => fn x => x
val c1 = fn f => fn x => f x
val c2 = fn f => fn x => f (f x)
val c3 = fn f => fn x => f (f (f x))
val c4 = fn f => fn x => f (f (f (f x)))
。。。然后看看它们的类型:

val c0 = fn : 'a -> 'b -> 'b
val c1 = fn : ('a -> 'b) -> 'a -> 'b
val c2 = fn : ('a -> 'a) -> 'a -> 'a
val c3 = fn : ('a -> 'a) -> 'a -> 'a
val c4 = fn : ('a -> 'a) -> 'a -> 'a 
。。。在第二个函数之后出现类型('a->'a)->'a->'a。这是你要找的普通类型吗

前两个函数的类型不同只是因为类型推断算法选择了最通用的类型。对于第一个函数,'a->'b->'b('a->'a)->'a->'a一样,是一个更通用的类型。但您始终可以使用类型注释向编译器提供提示:

val c0 : ('a -> 'a) -> 'a -> 'a = fn f => fn x => x
val c1 : ('a -> 'a) -> 'a -> 'a = fn f => fn x => f x

。。。现在,所有函数都应该具有相同的类型。

您要做的是,应用一个称为类型推断的过程

一般原则包括三个步骤:

  • 首先,我们为变量和表达式分配未确定的类型(writed
    'Z
    'Y
    'X
    ,等等)

    • 如果表达式使用一个我们已经指定了类型的变量,那么我们就使用它。例如,如果
      three
      已经与类型
      int
      绑定,那么在
      val nine=three*three
      中,我们知道
      three
      具有类型
      int
    • 如果表达式使用一个我们已经分配了非平凡类型方案的变量(即,它是多态的),那么我们使用该方案,但用一个未确定的类型替换每个类型变量。例如,如果
      first
      已经与类型
      'a*'b->'a
      绑定,那么在
      val firstOfFirst=fn quartex=>first(first quartex)
      中,我们首先为类型
      'Z*'Y->'Z
      指定一个
      类型,另一个为类型
      'X*'W->'W
    • 如果表达式使用新绑定的变量(范围为
      fn
      rec
      ),则该变量的所有引用都必须具有完全相同的类型-此时不允许多态性。例如,在
      fn f=>(f1,f“one”)
      (最终给出一个类型错误)中,我们首先将所有出现的
      f
      分配给单个类型
      'Z
      。(导致类型错误的原因是,我们以后需要将其细化为
      int->'Y
      string->'Y
      ,这两种情况是相互矛盾的。这是因为标准ML不支持。)
    在您的示例中,
    val one=fn f=>(fn x=>fx)
    ,我们可以将
    f
    类型指定为
    'Z
    ,将
    x
    类型指定为
    'Y

  • 接下来,我们执行类型统一,在这里,我们识别不同子表达式类型中必须匹配的不同部分。例如,如果我们知道
    f
    有类型
    'Z->real
    ,而
    i
    有类型
    int
    ,那么如果我们看到
    fi
    ,我们可以将
    'Z
    int
    统一起来,并得出结论
    f
    有类型
    int->real

    • 关于类型统一有很多很多细节,但我认为它们几乎都是你所假设的,所以我不想讨论它们
    在您的示例中,由于
    f
    应用于
    x
    ,因此我们可以将
    'Z
    'Y->…
    统一,并最终指定
    f
    类型
    'Y->'x
    。因此,表达式作为一个整体具有类型
    ('Y->'X)->'Y->'X

  • 最后,我们执行类型泛化。一旦我们完成了所有可以完成的统一——一旦我们完成了