performance - Slow tail recursion in F# -


I have an F # function which returns a zero-leaving pattern in the list starting with 0, n Choose, do not skip, select ... for a limit, for example, this function for input 2 is [2, 3, 6, 7, 10, 11 ...] .

In the beginning, I have implemented it as a non-tail - as the Recognitive function below:

  Start the start for the REC indexes maxSize = match Get started | When i & gt; Max-Size - & gt; [] | _ - & gt; [Initially for Jammu .. (Block Minimum + Start Max Max) - 1) - & gt; J] @indesasforstep (start + 2 * block siege) blocks max extension max   

to think that tail recurrence is desirable, I am re-implementing it using a list of cache list

  Issue Index - Start Blocking Forest Teller Maximum Size = Submit Forrestinant Issue = REC Index = Give ITR With List. When i & gt; Max-Size - & gt; AccumList | _ - & gt; Indiors Forest Initial (Instant + 2 * Block Seiz) (accumList @ [for for j in isartart .. ((Minimum (icetect + block siege maximal maximum) - 1) -> J] Index forest intonation start [] < / Code>  

However, when I have to fill 1, 1 and 20,000 (i.e. [1, 3, 5, 7 ...] up to 20,000) under Mao To run it in FSI, the tail is a much slower version than the first version (12 seconds compared to sub-second).

Tails-recursive version Why is it slow? Is this list due to insertion? Is it a compiler optimization? Have I actually implemented it in tail- recurrently?

I also feel like doing this Should use high-order functions, but I'm not sure how to do this.

Dave explains, the problem is that you are using the @ operator Adding tail is a more important performance issue with tail-recovery. In fact, tail-recycling actually does not give much speed to the program (but it works on large inputs where the stack overflow occurs).

The reason that you slow down the second version is that you have a long list generated by using a short list ( [...] ( accumList ) It is slow to add a long list to a small list (because the operation needs to be copied the first list).

You can fix it by collecting the elements in a reverse order in a narrow order. And then return it before returning the result:

  index Start the Forrestipel Block Maximum Size = Rick Index Forest Internal Install Deposit = Art With Attachment I When I> Max-Size -> AccumList |> List.REV | _ -> ACC = [For maximize (for mint (istart + blockSize) - 1) .. -1 .. Easter -> J] @ accumulation list index forest inalen (Easter + 2 * blocks) ACC indices forest initialization [ ]   

As you can see, there is less list in it (using Generate [...] ) and @ and on my machine, it is similar to the performance of non-tail-recursive version. Note that the [...] elements are generated in the order specified in the order - so that they can return back to the end.

You can write the whole thing more well using F # seq {..} syntax. You can use the @ operator entirely, because it allows you to provide different elemetns using yield and yield! Start Forrestive Block for REC Indexes: MaxSize = SEQ Sync {Start with match | When i & gt; Max-Size - & gt; () | _ - & gt; Initially for Jammu .. ((min + start + blockSize maxSize) - 1) Generate yield! Index foresteepsek (start + 2 * block siege) blocksis max scegs}

In this way I will write it. When calling it, you only have to add Seq.toList to evaluate the entire lazy sequence. The performance of this edition is similar.

Edit With the improvements from Daniel, the Seq version is really a bit faster!

Comments