Recursion 数字类型推断
我在SML中有这个表达式,需要找到它的最一般类型。当运行编译器时,我得到了下面显示的内容。我怎样才能找到最普遍的类型,不仅是这个函数,还有其他函数,比如教堂数字函数“2” 为什么是这种类型: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
('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
。。。现在,所有函数都应该具有相同的类型。您要做的是,应用一个称为类型推断的过程 一般原则包括三个步骤:
'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
,这两种情况是相互矛盾的。这是因为标准ML不支持。)string->'Y
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