let rec zip (lst:(int list) list) (lst2:int list)= match lst,lst2 with
|_,[]->lst
|[],_->[] (*never reach here*)
|(x::xs),(y::ys)->[x::y;(zip xs ys)]
Yup,[]适用于所有空案例但另一个问题..为什么ocaml将x :: y识别为int而不是int list?它给了我反馈,x :: y的类型为int,但是需要类型为int list
答案 0 :(得分:3)
空列表[]
是多态的,即每个列表类型都相同。
# [];;
- : 'a list = []
您可以通过注释表达式来强制输入类型:
# ([] : int list list);;
- : int list list = []
#
<强>更新强>
::
运算符左侧有一个元素,右侧有一个列表。您似乎正在尝试将其应用于两个元素。
答案 1 :(得分:1)
如果x
通过解构来自int list list
值的前面,则它必须是int list
类型。如果y
来自int list
,则其必须为int
类型。
因此,x::y
可能应该y::x
来获得int list
。
看来你可以得到几乎相同的结果:
let zip = List.map2 (fun a b -> b::a)
虽然这个函数需要参数作为相同长度的列表,而你的代码可以容纳不同的长度,并从任一列表中丢弃额外的元素。
此外,此函数返回一个“平面”列表列表,您可以尝试将int list
包裹在连续的列表层中(如俄罗斯娃娃)。这不会进行类型检查,因此您将不得不考虑如何使用括号列表表达式构建列表而不使用。
答案 2 :(得分:1)
首先,我们首先应该看看你的通用zip的预期类型。如果我理解正确,你会得到两个参数,其中lst是整数列表的列表,lst2是整数列表。我们现在想要并行迭代两个列表,以将lst2的当前元素追加到lst中的相应元素。这意味着,zip的结果类型与lst相同,即(int list)list。
现在,如果你返回一个列表[...],它的所有元素必须是类型(int list)。特别是此列表的第一个元素x :: y必须具有此类型。现在让我们看一下::的类型,列表构造函数。它将一个元素添加到列表中并返回新元素,因此其类型为&#39; a - &gt; (&#39;列表) - &gt; (&#39;列表)。在当前情况下,我们期望得到一个int列表,因此具体实例是int - &gt; (int list) - &gt; (int列表)。但是你传递了一个类型为(int list)的x作为第一个参数,那就是错误信息的来源。
正如其他人所指出的,如果你改为添加元素(y :: x),那么第一个元素的类型是正确的。如果你真的想要追加,你可以使用List append x [y],但这会恶化你的算法的计算复杂性,因为每个列表都必须为追加迭代。
最后一步,让我们修复列表的其余部分。第二个参数是带有type(int list)列表的zip的结果。如果将其打包到外部列表中,结果类型将变为((int list)list)列表,该列表与第一个元素和预期结果类型不兼容。你想要做的是将新列表添加到递归的结果,即你想使用列表构造函数::,而不是嵌套列表。
您的程序将变为:
let rec zip (lst:(int list) list) (lst2:int list)= match lst,lst2 with
|_,[]-> lst
|[],_->[] (*never reach here*)
|(x::xs),(y::ys)->
(List.append x [y]) ::(zip xs ys)
完成这项工作:
# zip [[1;2];[3;4]] [7;8;9];;
- : int list list = [[1; 2; 7]; [3; 4; 8]]