So I have this function which seems to be non-tail-call friendly, right?
let rec insertFooInProperPosition (foo: Foo) (bar: list<Foo>): list<Foo> =
match bar with
| [] -> [ foo ]
| head::tail ->
if (foo.Compare(head)) then
foo::bar
else
head::(insertFooInProperPosition foo tail)
Then I try to figure out how to use an accumulator so that the last thing done by the function is call itself, and I come up with this:
let rec insertFooInProperPositionTailRec (foo: Foo) (headListAcc: list<Foo>) (bar: list<Foo>): list<Foo> =
match bar with
| [] -> List.concat [headListAcc;[ foo ]]
| head::tail ->
if (foo.Compare(head)) then
List.concat [headListAcc; foo::bar]
else
insertFooInProperPosition foo (List.concat [headListAcc;[head]]) tail
let rec insertFooInProperPosition (foo: Foo) (bar: list<Foo>): list<Foo> =
insertFooInProperPositionTailRec foo [] bar
However, as far as I understand, the usage of List.concat would make this function much less efficient, right? So then how would I go and do this conversion properly?
Your solution looks ok if using recursion is required. However, the this task can be achieved without recursion (and a bit faster).
To concatenate two lists the first list should be copied and its last element should point to the first element of the second list. This is O(N) where N is the size of the first list. Growing list at the tail requires multiple concatenations, resulting traversing list for each N, which makes the complexity quadratic (hope I right here).
Instead of recursive approach that adds items to the list, the faster approach would be probably to find the insertion index and then copy all the items before it in one go and then concat it with new item and the rest of the list. This requires only three passes through the list so O(N).