Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this a good example of tail recursion in F#?

let  shuffley (numbers:int list) =
    let rec loop numbers acc =
        match numbers with
        | head::tail -> loop (List.rev(tail)) (head::acc)
        | [] -> List.rev(acc)
    loop numbers []
shuffley [1;2;3;4;5;6;7;8]

I am trying to practice some F# and I was wondering if could be a good example of tail recursion or this is just some nonsense.

like image 333
Second Son Avatar asked Jan 20 '16 01:01

Second Son


1 Answers

It is tail-recursive but you are calling List.rev once per element of your input list -

shuffley [1;2;3;4;5;6;7;8] = // ...
  // numbers                     acc
loop [1;2;3;4;5;6;7;8]           []
loop (List.rev [2;3;4;5;6;7;8])  [1]
loop (List.rev [7;6;5;4;3;2])    [8;1]
loop (List.rev [3;4;5;6;7])      [2;8;1]
loop (List.rev [6;5;4;3])        [7;2;8;1]
loop (List.rev [4;5;6])          [3;7;2;8;1]
loop (List.rev [5;4])            [6;3;7;2;8;1]
loop (List.rev [5])              [4;6;3;7;2;8;1]
loop (List.rev [])               [5;4;6;3;7;2;8;1]
List.rev [5;4;6;3;7;2;8;1]
[1;8;2;7;3;6;4;5]

List.rev is O(n) and so as the input grows, the process for shuffley grows exponentially. Does that make this a good example of tail recursion in F#? Probably not. For this particular program, we only need to reverse the input once -

let shuffley l =
  let rec loop xx yy zz r =
    match xx, yy, zz with
    | _::_::xx, y::yy, z::zz -> loop xx yy zz (z::y::r)
    | _::xx   , y::_ , _     -> List.rev (y::r)
    | _                      -> List.rev r
  loop l l (List.rev l) []

printfn "%A" (shuffley [1;2;3;4;5;6;7;8])
// ...

This loop matches two xx per iteration and spawns a very straightforward process -

  // xx                yy                zz                r
loop [1;2;3;4;5;6;7;8] [1;2;3;4;5;6;7;8] [8;7;6;5;4;3;2;1] []
loop [3;4;5;6;7;8]     [2;3;4;5;6;7;8]   [7;6;5;4;3;2;1]   [8;1]
loop [5;6;7;8]         [3;4;5;6;7;8]     [6;5;4;3;2;1]     [7;2;8;1]
loop [7;8]             [4;5;6;7;8]       [5;4;3;2;1]       [6;3;7;2;8;1]
loop []                [5;6;7;8]         [4;3;2;1]         [5;4;6;3;7;2;8;1]
List.rev [5;4;6;3;7;2;8;1]
[1;8;2;7;3;6;4;5]
like image 118
Mulan Avatar answered Oct 21 '22 05:10

Mulan