2009-08-20 61 views
4

我刚刚学习f#,所以可能我做的事情非常愚蠢。随意将我指向相关文档,我已经搜索但无法找到。我在Windows 7(.Net 4.0)上使用Visual Studio 2010测试版。f#中的缩进问题(vs2010 beta1)

一切顺利,我的第一个f#项目。好吧,几乎所有东西。特别 我正在写一个非常简单的线性插值功能,用下面的代码:

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 

,我收到了一系列完全逃避我的理解错误。

这是错误和警告的列表:

  • “的错误在返回表达这个‘让’可能正确的缩进。”为第一,第二和最后一个“让”。

  • “可能不正确缩进:该令牌是越位上下文开始于位置(39:10)尝试缩进该令牌还或使用标准格式约定”为“如果”

  • “不完整的结构化构建体在表达的最后一行(结果)“中或之前。

我补充一点,我不得不把汗有点注释类型,因为某种原因不明给我的编译器能够正确地推断出第一列表,但对于第二类型总是推断为单位另外,我原来的版本没有名字绑定的结果,而是简单地“返回的表达”,就像在

if x <= xvalues.Head then 
    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) 
     y0 + (y1-y0)/(x1-x0)*(x - x0) 

这留下一个错误下的“for”说“该表达式具有类型单位,但在此处与double类型一起使用”,并且“if”可能不正确地缩进。

我认为,当我看到解决方案时,我会觉得很愚蠢,但我一直被困在这样一个简单的问题上一个多小时,所以我要求你的帮助。

在此先感谢!

PS:我已经检查了标签被正确地解释为在工具 - >选项空间 - > ... - > F# - >选项菜单

PPS:这是我对SO的第一个问题:-)

+0

我很惭愧,但在代码中出现了明显的错误---)这证明我太老,无法在深夜编码。 为此,由于idx表示第一个大于或等于x的项,所以'let x0 = xvalues.Item(idx - 1)'和'let x1 = xvalues.Item idx'。 – Francesco 2009-08-20 08:55:42

回答

5

你的问题是,像

let result = yvalues.Head 

不是一个完整的表达,所以它不能形成if块的分支之一的身体。您的初始方法是正确的,只是for ... do循环没有返回有意义的值(它返回(),这是unit类型的唯一值,因为编译器试图解释;这类似于C#等语言中的void) 。代替for循环,您需要使用具有所需值的表达式。对你的代码的最小改变是使用你在循环中强制设置的可变值。更习惯的方法是使用像List.fold这样的内置函数来将列表压缩为单个值。这很复杂,因为您需要访问列表中的连续条目(并且您需要同时对xvalues和yvalues进行操作),这意味着您可能需要使用List.zip和Seq.pairwise,这可能会降低不习惯于F#的人的清晰度。

此外,还有一些其他更改可以用于使代码更具惯用性。例如,let x0 = xvalues.Item idx通常会写成let x0 = xvalues.[idx]。但是请注意,F#列表是不可变的,链接列表,因此不支持快速随机访问。这是支持使用内置List运算符的方法的另一个原因。

+0

谢谢,现在我更好地理解错误的含义。例如。如果x <= xvalues.Head then let result = yvalues.Head in 和“in”会提醒我,我绑定了一个名称局部范围和缺少表达式(我正在读取f#spec中的第6.7章绑定表达式)。在我看来,for ... do循环会执行其副作用,是吗? 感谢您提供更多惯用代码的建议。我只是在学习,所以我仍然很笨拙。我会用Seq.pairwise尝试一种方法。 – Francesco 2009-08-20 09:37:52

5
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)