Indentation problem in f # (vs2010 beta1)

I am just learning f #, so maybe I am doing something very stupid. Feel free to tell me the relevant documentation that I was looking for but could not find. I am using the beta version of Visual Studio 2010 on Windows 7 (.Net 4.0).

Everything is going well with my first f # project. Well .. almost everything. In particular, I am writing a very simple linear interpolation function with the following code:

let linterp (x:double) (xvalues:double list) (yvalues:double list) = let num_els = xvalues.Length if x <= xvalues.Head then let result = yvalues.Head elif x >= (List.rev xvalues).Head then let result = (List.rev yvalues).Head else for idx in [0 .. num_els] do if List.nth xvalues idx >= x then let x0 = xvalues.Item idx let y0 = yvalues.Item idx let x1 = xvalues.Item (idx+1) let y1 = yvalues.Item (idx+1) let result = y0 + (y1-y0)/(x1-x0)*(x - x0) result 

and I get a number of errors that completely elude my understanding.

This is a list of errors and warnings:

  • "in the returned expression for this let. Possible correct indentation for the first, second and last let.

  • “Possible wrong indentation: this token is in the offside context started at position (39:10). Try to postpone this token further or use standard formatting conventions" for "if"

  • "incomplete structured construction at or to this point in the expression" for the last line (result).

I will add that I had to sweat a bit in order to annotate the types, because for some reason I do not know that the compiler made the right conclusion for the first list, but for the second the type was always output as one. In addition, my original version did not bind the result of the name, but simply “returned the expression”, as in

 if x <= xvalues.Head then yvalues.Head 

or

 else for idx in [0 .. num_els] do if List.nth xvalues idx >= x then let x0 = xvalues.Item idx let y0 = yvalues.Item idx let x1 = xvalues.Item (idx+1) let y1 = yvalues.Item (idx+1) y0 + (y1-y0)/(x1-x0)*(x - x0) 

This results in an error for the "for" value saying that "this expression has a unit of type, but is used here with the double type" and that "if" may have the wrong indent.

I think that when I see a solution to this, I will feel stupid, but I tried such a simple problem for more than an hour, so I ask you for help.

Thanks in advance!

ps: I checked that the tabs are correctly interpreted as spaces in the menu Tools-> options → .... → F # → Tabs

pps: this is my first question about SO :-)

+4
source share
2 answers

Your problem is something like

 let result = yvalues.Head 

is not a complete expression and therefore cannot form the body of one of the branches of the if block. Your initial approach was correct, except that the for ... do loop does not return a meaningful value (it returns () , which is the only value of type unit , as the compiler tries to explain, this is similar to void in languages ​​like C # ) Instead of a for loop, you want to use an expression that has the value that you are looking for. The smallest change to your code will be to use a mutable value that you will definitely set in a loop. A more idiomatic approach would be to use a built-in function of type List.fold to compact the list to a single value. This is complicated by the fact that you need to access sequential entries in your lists (and you need to work on both x and yvalues ​​at the same time), which means you probably have to use List.zip and Seq .pairwise, which may reduce clarity for someone not used for F #.

In addition, there are several other changes you can apply to make your code more idiomatic. For example, let x0 = xvalues.Item idx usually written let x0 = xvalues.[idx] . However, note that F # lists are immutable, linked lists, and therefore do not support fast random access. This is another reason to favor an approach that uses the built-in List operators.

+5
source
 let linterp x (xvalues:double list) (yvalues:double list) = if x <= xvalues.Head then yvalues.Head elif x >= (List.rev xvalues).Head then (List.rev yvalues).Head else let idx = List.findIndex (fun e -> e >= x) xvalues let x0 = xvalues.Item idx let y0 = yvalues.Item idx let x1 = xvalues.Item (idx+1) let y1 = yvalues.Item (idx+1) y0 + (y1-y0)/(x1-x0)*(x - x0) 
+5
source

All Articles