Types 要统一的类型变量出现在类型中
我有一个函数可以从两个列表中重建一棵树。我返回一个关于所有分支的列表,但是我得到了一个我不理解的错误。但我认为这与返回类型有关 错误是:Types 要统一的类型变量出现在类型中,types,compiler-errors,sml,unification,Types,Compiler Errors,Sml,Unification,我有一个函数可以从两个列表中重建一棵树。我返回一个关于所有分支的列表,但是我得到了一个我不理解的错误。但我认为这与返回类型有关 错误是: Can't unify ''a with ''a list (Type variable to be unified occurs in type) Found near recon ( ::( preoH, preoT), ::( inoH, ...)) Exception- Fail "Static errors (pass2)" raised 出现错误
Can't unify ''a with ''a list (Type variable to be unified occurs in type) Found near recon
( ::( preoH, preoT), ::( inoH, ...))
Exception- Fail "Static errors (pass2)" raised
出现错误的那一行是函数定义的标题fun recon(preoH::preoT,inoH::inoT)=
这个错误到底意味着什么?为什么会发生
(* Reconstruts a binary tree from an inorder and a preorder list. *)
fun recon (preoH::preoT, inoH::inoT) =
(* Case 0: Leaf reached*)
if
preoT = [] andalso inoT = [] andalso preoH = inoH
then
[preoH]
else
let
(* split the list of nodes into nodes to the left and nodes to the
right of preoH; ST stands for subtree *)
val (inoLST, inoRST) = splitat (inoH::inoT, preoH)
val (preoLST, preoRST) = splitafter (preoT, last(inoLST))
in
(* Case 1: Unary branch encountered, make preoH the parent node of the
subtree and combine the left and right preorder and inorder lists*)
if
length(inoLST) <> length(preoLST)
then
[preoH, recon (preoLST@preoRST, inoLST@inoRST)]
(* Case 2: Binary branch encountered, proceed as normal *)
else
[recon (preoLST, inoLST), preoH, recon (preoRST, inoRST)]
end;
(*从顺序和预顺序列表中重建二叉树。*)
趣味侦察(preoH::preoT,inoH::inoT)=
(*案例0:已到达叶*)
如果
preoT=[]和also inoT=[]和also preoH=inoH
然后
[preoH]
其他的
让
(*将节点列表拆分为左侧节点和右侧节点
优先权;ST代表子树*)
val(inost,inoRST)=拆分(inoH::inoT,preoH)
val(前一次,前一次)=拆分后(前一次,最后一次(前一次))
在里面
(*情况1:遇到一元分支,将preoH设为
子树,并组合左、右预排序和顺序列表*)
如果
长度(初始)长度(初始)
然后
[预演,侦察](preoLST@preoRST, inoLST@inoRST)]
(*情况2:遇到二进制分支,继续正常操作*)
其他的
[侦察员(先发,先发),先发,侦察员(先发,先发)]
结束;
用某物统一变量意味着为变量找到一个等于该某物的值。例如,我们可以统一一些简单的东西,比如(我将使用三重相等表示两项必须相等):
统一的结果是我们可以用a
代替的值。在这种情况下,我们可以用int
代替a
,方程将保持不变(类似于数学中求解方程组):
或者我们可以统一一个稍微复杂一点的方程:
a -> int === bool -> b
在这里,我们需要找到需要替换a
和b
的值,以便方程成立。这些是a的bool
和b的int
:
a: bool
b: int
---------------------------
bool -> int === bool -> int
我希望你现在已经有了这个想法。在您的情况下,编译器必须统一这一点:
a === a list
好吧,在你的错误消息中,它是“a
,而不仅仅是a
,但我们暂时可以忽略它。问题是,由于a
出现在两侧,因此等式是不可统一的,因此错误消息(emphasis mine)中的提示“Type变量要统一出现在Type”中。如果我们说a
必须是a列表
,并用两边的a
替换,我们会得到以下结果:
a list === a list list
我们还没有删除需要求解的变量,我们也不会很快删除。这就是为什么编译器会出错,它会导致一个无限循环,一个简单的检查变量不会出现在等式的两边是避免该循环的好方法
你为什么会这样?简短的版本是,您试图使用嵌套列表表示树,而SML的类型系统无法处理该问题。您试图根据列表构建的树类似于:
[[a], a, [a]]
其中a
是某种泛型类型变量。列表是同质容器,它们只能包含单一类型的值,这意味着[a]
和a
必须是相同的类型,即:
a === a list
我已经解释了为什么这会导致错误
解决方案是使用递归的数据类型来表示树,例如:
datatype 'a tree =
Leaf
| Node of { value : 'a, left: 'a tree, right: 'a tree }
这是因为它允许我们递归地定义它,也就是说,叶子的类型是树本身。您的recon
函数的返回类型应该是''树
希望现在能更清楚一点
Ionut全面解释了类型统一的工作原理,因此这里有一个提示:
[preoH, recon (preoLST@preoRST, inoLST@inoRST)]
第一个元素具有类型“a”,第二个元素具有类型“a”列表
第二个元素具有类型“a”,第一个和第三个元素具有类型“a”列表
>P>当您检查列表为空时,考虑使用<代码> null PROOT ,或使用模式匹配处理该情况。
@约翰克莱曼谢谢你,先生!非常感谢,尤其是来自一位教授。@IonuțG.Stan:recon
可能应该在树中键入“列表->”或“列表->”,因为元素正在相互比较。@SimonShine你是对的。我只是想避免解释'a
和'a
之间的区别,但这可能会导致更多的混淆。如果您碰巧对ML中的类型推断工作方式感兴趣,我已经对此进行了一个简短的讨论:我希望口音可以忍受。
datatype 'a tree =
Leaf
| Node of { value : 'a, left: 'a tree, right: 'a tree }
[preoH, recon (preoLST@preoRST, inoLST@inoRST)]
[recon (preoLST, inoLST), preoH, recon (preoRST, inoRST)]