SML Error:Types of if branches do not agree
SML Error:Types of if branches do not agree
我正在尝试查找某个元素是否是集合的一部分。这是我的功能:
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]))
它将 return 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 列表”以及如何修复此错误?
What is a 'Z list?
A 'Z 列表是标准 ML 在基本情况下推断 nil
的 return 类型的方法。 nil
可以是任何类型的列表,因为它是空的。 'Z 是类型变量。
How do I fix this error?
问题是 elementOf
有时 return nil
有时 true
/ false
。通过将 base-case 更改为 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)
或使用 built-in 列表组合器 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))
编译器已确定“then”分支必须 return 类型 bool
,但“else”分支必须 return 类型 'Z list
。 'Z list
类型的意思是“一个列表,其元素可以是任何东西”。以 '
开头的类型是类型变量,如果编译器确定并非所有类型都是可能的,则稍后可能会被另一种类型替换,或者如果类型可以是多态的,则可能最终保留下来。
“then”分支必须是布尔值,因为它是 z
,给定匹配构造中的模式是上面模式指定的类型为 bool list
的列表的第一个元素. “else”分支必须是一个列表,因为它是对 elementOf
的调用,并且模式匹配中的第一个 case 有 elementOf
return nil
这是一个列表(与对元素的类型没有限制:由于空列表没有元素,它的元素可以说是您愿意选择的任何类型)。
鉴于函数的用途,它应该 return 一个布尔值,因此在第一种情况下 returning nil
没有意义。空列表编码一个没有元素的集合,所以你应该 return false
那里。
您似乎将集合表示为 (U,V)
,其中 U
是通用集合,V
是布尔向量(均表示为相同长度的列表)。这当然是合理的,尽管正如@SimonShine 在他的出色回答中所暗示的那样,这并不是最有效的。
使用您的表示,您可以使用模式匹配定义您的函数,让 SML type-inference 为其推断最通用的类型:
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));
我正在尝试查找某个元素是否是集合的一部分。这是我的功能:
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]))
它将 return 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 列表”以及如何修复此错误?
What is a 'Z list?
A 'Z 列表是标准 ML 在基本情况下推断 nil
的 return 类型的方法。 nil
可以是任何类型的列表,因为它是空的。 'Z 是类型变量。
How do I fix this error?
问题是 elementOf
有时 return nil
有时 true
/ false
。通过将 base-case 更改为 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)
或使用 built-in 列表组合器 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))
编译器已确定“then”分支必须 return 类型 bool
,但“else”分支必须 return 类型 'Z list
。 'Z list
类型的意思是“一个列表,其元素可以是任何东西”。以 '
开头的类型是类型变量,如果编译器确定并非所有类型都是可能的,则稍后可能会被另一种类型替换,或者如果类型可以是多态的,则可能最终保留下来。
“then”分支必须是布尔值,因为它是 z
,给定匹配构造中的模式是上面模式指定的类型为 bool list
的列表的第一个元素. “else”分支必须是一个列表,因为它是对 elementOf
的调用,并且模式匹配中的第一个 case 有 elementOf
return nil
这是一个列表(与对元素的类型没有限制:由于空列表没有元素,它的元素可以说是您愿意选择的任何类型)。
鉴于函数的用途,它应该 return 一个布尔值,因此在第一种情况下 returning nil
没有意义。空列表编码一个没有元素的集合,所以你应该 return false
那里。
您似乎将集合表示为 (U,V)
,其中 U
是通用集合,V
是布尔向量(均表示为相同长度的列表)。这当然是合理的,尽管正如@SimonShine 在他的出色回答中所暗示的那样,这并不是最有效的。
使用您的表示,您可以使用模式匹配定义您的函数,让 SML type-inference 为其推断最通用的类型:
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));