简体   繁体   中英

F# Error: Value cannot be reference and If Else statement

I am converting C# code to F# code. For some reason, the compiler does not like how I call methods in the F# file.

I don't know why the ReturnClosestInList and findYGivenTwoPointsInSameGraph cannot be referenced. For the if then else , should I use a let to bind the finish ? I don't know why it detects it as bool instead of int . Anyone know why I got these errors and perhaps can suggest a better way to write this?

This is my C# code:

    // find point on graph with given Rc
    private Coordinate GetXY(Dictionary<double, double> cons)
    {
        if (cons.ContainsKey(input))
            return new Coordinate(input, cons[input]);
        else
        {
            //Rc is not found, use interpolation to find point at given Rc.
            List<double> index = ReturnClosestInList(new List<double>(cons.Keys), 0, cons.Count - 1);
            System.Diagnostics.Debug.WriteLine("index1 " + index[0]);
            System.Diagnostics.Debug.WriteLine("index2 " + index[1]);
            return FindClosest(index, cons);
        }
    }

    //formula to find y, given 2 points in the same graph
    private Coordinate FindClosest(List<double> index, Dictionary<double, double> cons)
    {
        double y = cons[index[0]] + ((input - index[0]) / (index[1] - index[0])) * (cons[index[1]] - cons[index[0]]);
        return new Coordinate(input, y);
    }

    //formula to find y, given 2 points from 2 graphs
    private Coordinate FindClosest2(Coordinate p1, Coordinate p2)
    {
        double y = p1.Y + ((givenLine - p1.X) / (p2.X - p1.X)) * (p2.Y - p1.Y);
        //System.Diagnostics.Debug.WriteLine("y is " + y);
        return new Coordinate(givenLine, y);
    }

    //binary search for 2 closest Rc value in the given vi graph.
    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] };
    }

This is my current F# code.

let Keys(map: Map<_, _>) =
    seq{
        for KeyValue(key) in map do
            yield key
    }


let findPointXYGivenRc (cons : Map<double, double>) (input : double) = 
    let output = if (cons.ContainsKey(input)) then
                    let c = new Coordinate(cons.[input], input)
                    c
                 else
                    let list = ReturnClosestInList Keys cons 0 (cons.Count - 1) input
                    let c = findYGivenTwoPointsInSameGraph list cons input
                    c                       
    output

let findYGivenTwoPointsInSameGraph (index : Map<int, double>) (cons : Map<double, double>) (input : double) =
    let y = cons.[index.[0]] + (input - index.[0]) / (index.[1] - index.[0]) * (cons.[index.[1]] - cons.[index.[0]])
    let c = new Coordinate(input, y)
    c

let findYGivenTwoPointsFromTwoGraphs (p1 : Coordinate) (p2: Coordinate) (givenLine : double) = 
    let y = p1.Y + (givenLine - p1.X) / (p2.X - p1.X) * (p2.Y - p1.Y);
    let c = new Coordinate(givenLine, y)
    c

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

    finish = if finish < 0 then 
                start + 1
             else finish

This is my first error

第一个错误

This is my second error:

第二个错误

Your first error where it can't "find" ReturnClosestInList is because ordering matters in F# code. ReturnClosestInList has to be defined before findPointXYGivenRc and so on:

let g () = f 12 // ERROR: 'f' isn't known to 'g' right here

let f x = ()

let h () = f 12 // Compiles: 'f' is already defined and known

You have three options:

  1. Re-order your F# functions in source to be in a top-down ordering. Things are defined before they are used.
  2. If you have mutually recursive functions you can define them as a set with let...and as in the example documentation. This isn't the case in the snippet you provided, but it may come up in the future.
  3. Consider using recursive modules when you have several things that all inter-depend on one another.

Your second error is a little more confusing, but you have two problems:

  1. Your if(finish >= start) then clause has no corresponding else .
  2. Your use of finish =... is saying "the value finish should be equal to the following expression".

The first sub-problem here is what leads to the compile error. An if in F# that doesn't have an else returns unit (same as void ). But you can't do that here, you need to return an actual value. Otherwise there's no indicator that anything completed/succeeded as you've defined it.

The second one comes up immediately after you fix the first one. Do you expect to return a bool here? If you do, then you can leave it. But if you don't, then you should just make the if expression the overall return.

What I think your function should look like is this:

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 
            start + 1
        else
            finish

This resolves both problems by making it a recursive function that returns a value and making it return an int rather than a bool .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM