要统一的类型变量出现在类型中

时间:2016-04-23 17:21:15

标签: types compiler-errors sml unification

我有一个从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;

2 个答案:

答案 0 :(得分:5)

用某种方法统一变量意味着找到与该东西相等的变量值。例如,我们可以统一一些简单的东西(我将使用三等于意味着两个术语必须相等):

a === int

统一的结果是我们可以用a代替的值。在这种情况下,我们可以用int代替a,方程将成立(它类似于求解数学方程组):

a: int
-----------
int === int

或者我们可以统一一个稍微复杂的等式:

a -> int === bool -> b

在这里,我们需要找到需要替换ab的值,以便等式成立。这些bool aint 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)

  1. Ionut全面解释了类型统一是如何工作的,所以这里有一个提示:

    [preoH, recon (preoLST@preoRST, inoLST@inoRST)]
    

    第一个元素的类型为'a ,第二个元素的类型为'列表

    [recon (preoLST, inoLST), preoH, recon (preoRST, inoRST)]
    

    第二个元素的类型为'a ,第一个和第三个元素的类型为'列表

  2. 当您检查列表为空时,请考虑使用null preoT,或使用模式匹配处理案例。