Reputation: 37
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:
Upvotes: 0
Views: 52
Reputation: 5005
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:
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.Your second error is a little more confusing, but you have two problems:
if(finish >= start) then
clause has no corresponding else
.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
.
Upvotes: 1