F#自定义追加功能

时间:2017-09-21 04:53:59

标签: list function recursion design-patterns f#

我有一个将list2追加到list1的自定义函数。

let append ls1 ls2 =
    let rec loop ls ls1 ls2 =
        match ls1, ls2 with
        | _, hd::tl -> 
            loop (hd::ls) ls1 tl
        | hd::tl, _ -> loop (hd::ls) tl ls2
        | _ -> ls
    loop [] ls1 ls2

工作正常。但问题是当我调用函数

let appended = append [1;2;3;4;5] [6;7;8;9;10]

而不是返回[1;2;3;4;5;6;7;8;9;10],它返回

[5;4;3;2;1;10;9;8;7;6]

它反转了两个列表。

2 个答案:

答案 0 :(得分:2)

以下代码为我制定了

let rec append list1 list2 = 
   match list1, list2 with
    | hd::tl, _ -> hd::(append  tl list2)
    | _, hd::tl -> hd::(append list1 tl)
    | _ -> []

以下代码的输出为:

   let List1 = [1; 3; 5];
    let List2 = [7]
    printf "%A" append List1 List2

[1; 3; 5; 7] 

答案 1 :(得分:1)

您需要撤消列表。 解决方案的一种方法是考虑rev函数的外观。 这是第一次尝试:

let rec rev lst =
    match lst with 
    | h::t -> (rev t)@[h]
    | [] -> []

这个函数反转一个列表,但是现在让我们做另一个使用累加器的版本,这意味着我们将使用另一个参数来代替在最后一行使用空列表:

let rec rev lst acc =
    match lst with 
    | h::t -> rev t (h::acc)
    | [] -> acc

所以现在我们必须将空列表作为参数传递:

rev [1..4] [];;

val it:int list = [4; 3; 2; 1]

您可能想知道为什么我们需要这样的功能,这个功能是tail recursive但是这不是您的问题,您希望附加两个列表。事实证明,这是您正在寻找的功能的90%。

如果不是传递空列表,而是传递第二个列表:

rev [1..4] [5..8];;

val it:int list = [4; 3; 2; 1; 5; 6; 7; 8]

很接近,但是,是的,第一个列表是颠倒的,好的,但我们有这个功能可以反转列表,所以让我们颠倒第一个列表:

rev (rev [1..4] []) [5..8] ;;

val it:int list = [1; 2; 3; 4; 5; 6; 7; 8]

很好,现在这个rev可以是我们的loop功能:

let append lst1 lst2 = 
    let rec rev lst acc =
        match lst with 
        | h::t -> rev t (h::acc)
        | [] -> acc
    rev (rev lst1 []) lst2

哪个按预期工作,但请注意我们只是调用两次参数化rev函数。希望您了解函数式编程如何允许您组合函数以解决不同的问题。在这种情况下,我们将一个函数与自身结合起来。