我有一个从2个列表重建树的功能。我在所有分支上返回一个列表,但是我收到一个我不理解的错误。但我认为它与返回类型有关。
错误是这样的:
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;
答案 0 :(得分:5)
用某种方法统一变量意味着找到与该东西相等的变量值。例如,我们可以统一一些简单的东西(我将使用三等于意味着两个术语必须相等):
a === int
统一的结果是我们可以用a
代替的值。在这种情况下,我们可以用int
代替a
,方程将成立(它类似于求解数学方程组):
a: int
-----------
int === int
或者我们可以统一一个稍微复杂的等式:
a -> int === bool -> b
在这里,我们需要找到需要替换a
和b
的值,以便等式成立。这些bool
a
和int
b
:
a: bool
b: int
---------------------------
bool -> int === bool -> int
我希望你现在有了这个想法。在您的情况下,编译器必须统一:
a === a list
嗯,你的错误信息中只有''a
而不只是a
,但我们暂时可以忽略它。问题在于,因为a
出现在两边,所以等式不可统一,因此错误消息中的提示(强调我的)“类型变量要统一发生在输入强>”。如果我们说a
必须a list
并将a
替换为双方,我们就会知道:
a list === a list list
我们尚未删除我们需要解决的a
变量,我们不会很快就会这样做。这就是为什么编译器barfs,它会导致无限循环,并且简单检查变量不会出现在等式的两边,这是避免该循环的好方法。
为什么会发生这种情况?简短版本是您尝试使用嵌套列表表示树,而SML的类型系统无法处理。您尝试根据列表构建的树看起来类似于:
[[a], a, [a]]
其中a
是一些泛型类型变量。列表是同类容器,它们只能包含单一类型的值,这意味着[a]
和a
必须属于同一类型,即:
a === a list
我已经解释了为什么会导致错误。
解决方案是使用递归datatype
来表示树,例如:
datatype 'a tree =
Leaf
| Node of { value : 'a, left: 'a tree, right: 'a tree }
这是有效的,因为它允许我们递归地定义它,即叶子的类型本身是tree
。您的recon
函数的返回类型应为''a tree
。
希望现在有点清楚了。
答案 1 :(得分:1)
Ionut全面解释了类型统一是如何工作的,所以这里有一个提示:
[preoH, recon (preoLST@preoRST, inoLST@inoRST)]
第一个元素的类型为'a ,第二个元素的类型为'列表。
[recon (preoLST, inoLST), preoH, recon (preoRST, inoRST)]
第二个元素的类型为'a ,第一个和第三个元素的类型为'列表。
当您检查列表为空时,请考虑使用null preoT
,或使用模式匹配处理案例。