合理地嵌套函数

时间:2017-11-04 10:19:01

标签: f#

我创建了一个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工作。我有兴趣更好地掌握这种方法的实际用途,我可以用较小的部分分解问题。

2 个答案:

答案 0 :(得分:4)

只需撰写combine,您就无法获得所需内容。最里面的combine将按预期工作,产生('a * 'b) list,但下一个会产生('a * 'b) list'c list,产生(('a * 'b) * 'c)) list,而不是('a * 'b * 'c) list {1}}您想要查看。

元组根本不会那样工作 - 你无法概括为任意长度的元组"。这就是为什么有单独的List.zipList.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))