Sophie Chai
Sophie Chai

Reputation: 37

How to Recursive call in F#

I am converting a c# recursive function to f#. I am not really familiar with F#. I had a bunch of errors with I dont know why. I did look up the recursive function syntax but with all the if statements I have, I am confused on how to write it in f#.

Here are the c# recursive function

    private List<double> ReturnClosestInList(List<double> allKey, int begin, int end)
    {
        if (end >= begin)
        {
            int mid = begin + (end - begin) / 2;
            if (allKey[mid] > input) return ReturnClosestInList(allKey, begin, mid - 1);
            return ReturnClosestInList(allKey, mid + 1, end);
        }
        if (end < 0) end = begin + 1;
        if (begin < 0) begin = end + 1;
        if (end > allKey.Count - 1) end = begin - 1;
        if (begin > allKey.Count - 1) begin = end - 1;
        return new List<double> { allKey[begin], allKey[end] };
    }

And here are the f# code that I wrote and the error:

let rec ReturnClosestInList (allKey : List<double>) (start : int) (finish : int) (input : double)= 
    if(finish >= start) then
        let mid = start + (finish - start) / 2
        if(allKey.[mid] > input) then
            ReturnClosestInList allKey start (mid - 1) input
        else ReturnClosestInList allKey (start + 1) mid input

    else
        if finish < 0 then 
            finish = start + 1
        elif start < 0 then
            start = finish + 1
        elif finish > allKey.Length - 1 then
            finish = start - 1
        else start > allKey.Length - 1 then
            start = finish - 1

    let c : List<double> = [allKey.[start]; allKey.[finish]]
    c

Upvotes: 0

Views: 107

Answers (1)

Tomas Petricek
Tomas Petricek

Reputation: 243096

There are two issues with your code. The first is that you are treating start and finish as mutable values. The other is that your else branch does not return a value.

To fix the former, I think the best way is to reassign the variable using something like this:

let start, finish = 
    if finish < 0 then 
        start, start + 1
    elif start < 0 then
        finish + 1, finish
    elif finish > allKey.Length - 1 then
        start, start - 1
    elif start > allKey.Length - 1 then
        finish - 1, finish
    else start, finish

The idea is that you are defining new variables of the same name and you assign them both a new value. As you need to update values of one or the other, the code reassigns both of them (with the else branch not doing anything special).

The first issue is that both branches of your if have to return a result. To do this, you need to write something like this:

if(finish >= start) then
    let mid = start + (finish - start) / 2
    if(allKey.[mid] > input) then
        ReturnClosestInList allKey start (mid - 1) input
    else ReturnClosestInList allKey (start + 1) mid input
else
    let start, finish = 
        // (all the code to tweak start/finish goes here)
    [allKey.[start]; allKey.[finish]]

This way, the return value of the if case is whatever you get from the recursive call. The return of the other case is whatever you build using [ ... ].

It is also worth noting that your code does not look very functional, so if you are learning F#, I'd recommend writing this using pattern matching rather than by converting code from C#. You'll get a much nicer and easier to understand solution.

Upvotes: 1

Related Questions