我创建了一个combine
函数,给定一个列表元组,返回一个元组列表:
let rec combine =
fun (l1, l2) ->
match (l1, l2) with
| ([], []) -> []
| (x::xs, y::ys) -> (x, y)::(combine xs ys)
然后我构建了一个类似的函数foo56
,其工作方式相同,但有四个列表而不是两个。
let rec foo76 = //Combine a 4-tuple of lists in a list of 4-tuples
fun (l1, l2, l3, l4) ->
match (l1, l2, l3, l4) with
([], [], [], []) -> []
| (x::xs, y::ys, z::zs, t::ts) ->
(x, y, z, t)::(foo76 (xs, ys, zs, ts))
问题:我希望通过foo56
实施combine
。我做了几次尝试,失败了。这是(叹气)最有希望的:
let foo76combine = //Combine a 4-tuple of lists in a list of 4-tuples
fun (l1, l2, l3, l4) ->
match (l1, l2, l3, l4) with
([], [], [], []) -> []
| (x::xs, y::ys, z::zs, t::ts) ->
(x, y, z, t)::(combine(combine(combine (xs, ys) zs) ts))
我无法想象如何以递归方式正确地嵌套combine
。我想,这可能是由于我的经验不足。至少我是在正确的道路上吗?这不仅仅是让foo76
工作。我有兴趣更好地掌握这种方法的实际用途,我可以用较小的部分分解问题。
答案 0 :(得分:4)
只需撰写combine
,您就无法获得所需内容。最里面的combine
将按预期工作,产生('a * 'b) list
,但下一个会产生('a * 'b) list
和'c list
,产生(('a * 'b) * 'c)) list
,而不是('a * 'b * 'c) list
{1}}您想要查看。
元组根本不会那样工作 - 你无法概括为任意长度的元组"。这就是为什么有单独的List.zip
和List.zip3
函数,而不是一般的List.zipN
。如果你想处理不同的元组大小,你需要不同的单独函数。
您可以通过映射生成的"嵌套"来补偿这种情况。将元组转换为4元组,但是重新使用combine
得到的东西在我看来并不值得麻烦 - 与专用函数foo76
相比,它更难以阅读且性能更低:
let rec zip4 (l1, l2, l3, l4) =
match l1, l2, l3, l4 with
| [], [], [], [] -> []
| x::xs, y::ys, z::zs, t::ts ->
(x, y, z, t) ::
(List.map
(fun (((a,b),c),d) -> (a,b,c,d))
(combine(combine(combine(xs, ys), zs), ts)))
答案 1 :(得分:2)
List.zip
是一个与您的combine
函数类似的现有函数。还有List.zip3
,它有3个列表,但没有内置List.zip4
。您可以按照List.zip
这样自己定义:
let zip4 a b c d =
a
|> List.zip b
|> List.zip c
|> List.zip d
|> List.map (fun (d, (c, (b, a))) -> (a, b, c, d))