这些代码有什么问题?

时间:2015-02-06 21:55:10

标签: ocaml

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

3 个答案:

答案 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]]