2015-02-06 87 views
0
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)] 

是,[]是为所有空案件,但另一个问题..为什么ocaml认识x :: y为int而不是int list?它给我的反馈是,x :: y的类型为int,但所需的类型为int list这些代码有什么问题?

回答

3

空列表[]是多态的,即每个列表类型都是相同的。

# [];; 
- : 'a list = [] 

您可以通过注释表达强制类型:

# ([] : int list list);; 
- : int list list = [] 
# 

更新

::运营商需要在左侧和元素,在右侧的列表中。它看起来像你试图将它应用于两个元素。

+0

THX非常..问题编辑。因为我发现原因不是空的int列表列表。对不起, – 2015-02-06 22:39:33

+0

“::”运算符在左边有一个元素,在右边有一个列表。不知道你想要什么结果,但我怀疑'x :: y'没有意义。 – 2015-02-06 23:09:31

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 s列入连续的列表层(如俄罗斯娃娃)。这不会进行类型检查,所以您将不得不考虑如何使用括号列表表达式来构造列表而不使用

1

首先,我们应该看看您的通用zip的预期类型。如果我理解正确,给出两个参数,其中lst是整数列表的列表,lst2是整数列表。我们现在想要并行迭代两个列表,以将lst2的当前元素附加到lst中的相应元素。这意味着,zip的结果类型与lst相同,即(int list)列表。

现在,如果您返回一个列表[...],它的所有元素必须是(int list)类型。特别是这个列表的第一个元素x :: y必须具有这种类型。现在让我们看看::的列表构造函数的类型。它将元素预先添加到列表中并返回新元素,因此它的类型是'a - >('list') - >('list')。在当前情况下,我们期望int列表作为结果,所以具体实例是int - >(int list) - >(int list)。但是你传递一个类型为(int list)的x作为第一个参数,这就是错误信息的来源。正如其他人已经指出的那样,如果你预先添加元素(y :: x),那么第一个元素的类型是正确的。如果你真的想追加,你可以使用List append x [y],但是这会加剧算法的计算复杂度,因为每个列表都必须迭代来追加。

作为最后一步,我们来修复列表的其余部分。第二个参数是类型为(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]]