我有一个非常简单的代码,它应该将元组列表(int * string)转换为两个列表,一个int列表和一个字符串列表 - 基本上是元组列表中的元组列表列表。
fun unzip_single_int[] : int list = []
| unzip_single_int(x::xs) : int list =
x :: unzip_single_int(xs)
fun unzip_single_string[] : string list = []
| unzip_single_string(x::xs) : string list =
x :: unzip_single_string(xs)
fun unzip[] : (int list * string list) = ([], [])
| unzip([twopls]) : (int list * string list) =
let
val x : int list = unzip_single_int(twopls);
val y : string list = unzip_single_string(twopls); (* this is line 28 btw *)
in
(x, y)
end
错误:
zip.sml:28.7-28.52 Error: operator and operand don't agree [tycon mismatch]
operator domain: string list
operand: int list
in expression:
unzip_single_int twopls
由于某种原因,编译器认为val y:string list = unzip_single_string(twopls)指的是一个int列表。
有趣的是,当我改变两个时,当我改变时:
val x : int list = unzip_single_int(twopls);
val y : string list = unzip_single_string(twopls);
到
val y : string list = unzip_single_string(twopls);
val x : int list = unzip_single_int(twopls);
错误也会切换:
zip.sml:28.7-28.47 Error: operator and operand don't agree [tycon mismatch]
operator domain: int list
operand: string list
in expression:
unzip_single_int twopls
出于某种原因,无论第二次呼叫是什么,它都会假设它的最后一个呼叫的类型是什么。它为什么这样做?我该如何克服这个问题?我在其他两个函数定义中清楚地表明它们分别是int列表和字符串列表,那么为什么SML认为我在将它明确定义为int列表时发送字符串列表?
谢谢!
答案 0 :(得分:3)
您的问题的答案是类型推断。您尚未获得twopls
的任何类型或unzip
的参数类型,并且当您为unzip_single_int(twopls)
进行值声明时,您正在调用x
。因此,SML推断twopls
是int list
,因为函数unzip_single_int
的类型是int list -> int list
,这意味着它需要int list
作为输入并返回int list
。
在SML推断twopls
是int list
后,您正试图致电unzip_single_string(twopls)
。但是,函数unzip_single_string
的类型为string list -> string list
,因此它需要string list
的表达式作为输入。但现在twopls
是int list
,因此您会收到类型错误。
但是,你的函数定义不会改变列表的任何内容,它们会返回完全相同的列表,我猜你希望它们返回元组中的第一个或第二个元素,所以你应该补充一点。您的unzip
函数应该具有(int * string) list -> int list * string list
类型。因此,请尝试对列表中的int * string
元素进行模式匹配。通常你会模仿匹配x :: xs
这样的列表,但是如果你知道元素是元组,并且你想要访问它们,你可以像(num, str) :: xs
那样模式匹配它们,其中num
是一个int
变量和str
是string
变量。你应该能够弄清楚其余部分。祝你好运!