SML错误:if分支的类型不一致

时间:2016-01-18 14:06:47

标签: sml smlnj

我试图找出一个元素是否是一个集合的一部分。这是我的功能:

fun elementOf(x:int, (nil:int list, nil:bool list)) = nil
  | elementOf(x, (y::ys, z::zs)) = if x = y then z else elementOf(x, (ys, zs));

因此,如果我致电elementOf(2, ([2,7,4], [false,true,false])),它将返回false

但是,我收到错误消息:

Error: types of if branches do not agree [tycon mismatch]
then branch: bool
else branch: 'Z list
in expression: if x = y then z else elementOf(x,ys,zs))

什么是' Z列表以及如何解决此错误?

3 个答案:

答案 0 :(得分:4)

  

什么是'Z列表?

'Z列表是标准ML在您的基本案例中推断nil的返回类型的方式。 nil可以是任何类型的列表,因为它是空的。 'Z是一个类型变量。

  

如何解决此错误?

问题在于,elementOf有时无法返回nil,有时会返回true / false。通过将基本大小写更改为false,该函数将起作用,使得不在列表中的元素也不在集合中:

fun elementOf(x:int, (nil:int list, nil:bool list)) = false
  | elementOf(x, (y::ys, z::zs)) = if x = y then z else elementOf(x, (ys, zs));

但是可能没有充分的理由存储不在集合中的元素,而不是将它们丢弃。稍微高效的表示只是一个成员列表:

fun elementOf (x, nil : int list) = false
  | elementOf (x, y::ys) = x = y orelse elementOf (x, ys)

或使用内置列表组合器List.exists

fun elementOf x xs = List.exists (y => x = y) xs

或用point-free style写的:

fun curry f x y = f (x, y)
val elementOf = List.exists o curry op=

更好的一个还依赖于二叉树:

data binTree = Empty
             | Node of binTree * int * binTree

fun elementOf (x, Empty) false
  | elementOf (x, Node (left, y, right)) =
    (case Int.compare (x, y) of
          LESS => elementOf (x, left)
        | EQUAL => true
        | GREATER => elementOf (x, right))

答案 1 :(得分:3)

编译器已确定“then”分支必须返回类型bool,但“else”分支必须返回类型'Z list。类型'Z list表示“其元素可以是任何内容的列表”。以'开头的类型是类型变量,如果编译器确定并非所有类型都是可能的,则稍后可能会被其他类型替换,或者如果类型可能是多态的,则最终可能会保留。

“then”分支必须是布尔值,因为它是z,它给出了match构造中的模式,是上面指定的模式类型为bool list的列表的第一个元素。 “else”分支必须是一个列表,因为它是对elementOf的调用,并且模式匹配中的第一个案例有elementOf返回nil这是一个列表(没有约束)元素类型:由于空列表没有元素,因此可以说其元素可以是您选择的任何类型。

鉴于函数的目的,它应返回一个布尔值,因此在第一种情况下返回nil没有意义。空列表编码没有元素的集合,因此您应该返回false

答案 2 :(得分:1)

您似乎将集合表示为(U,V),其中U是通用集,V是布尔向量(均表示为相同长度的列表)。这当然是合理的,尽管@SimonShine在其出色的答案中表明它不是最有效的。

使用你的表示法,你可以使用模式匹配来定义你的函数,让SML的类型推断推断出最常用的类型:

fun elementOf (x,([],[])) = false
|   elementOf (x,(y::ys,z::zs)) = if x = y then z else elementOf (x,(ys,zs));

推断类型是

''a * (''a list * bool list) -> bool

''a引用任何相等类型 - 因此您的函数可用于表示任何类型的集合(只要该类型具有相等的概念)而不仅仅是整数。例如,elementOf ("cat",(["the","cat","in","hat"],[true,true,false,true]))评估为true

在SML / NJ中,定义会发出警告:Warning: match nonexhaustive。这是因为定义假设列表长度相同。您可以按原样保留代码 - 如果您的布尔列表与通用集的长度不同,则函数可能会崩溃,或者您可以认为false是合理的默认值并将定义修改为:

fun elementOf (x,([],_)) = false
|   elementOf (x, (_,[])) = false
|   elementOf (x,(y::ys,z::zs)) = if x = y then z else elementOf (x,(ys,zs));