我试图找出一个元素是否是一个集合的一部分。这是我的功能:
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列表以及如何解决此错误?
答案 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));