f# 中的缩进问题(vs2010 beta1)

发布于 2024-08-01 22:35:19 字数 1801 浏览 1 评论 0原文

我刚刚学习 f#,所以可能我正在做一些非常愚蠢的事情。 请随意向我指出相关文档,我已经搜索过但无法找到。 我在 Windows 7 (.Net 4.0) 上使用 Visual Studio 2010 beta。

我的第一个 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

我收到了一系列完全无法理解的错误。

这是错误和警告的列表:

  • “此 'let' 的返回表达式中出现错误。第一个、第二个和最后一个“let”的可能正确缩进”。

  • “可能不正确的缩进:此标记超出了从位置 (39:10) 开始的上下文。尝试进一步缩进此标记或使用标准格式约定”作为“if”

  • 最后一行的“if”

    “在表达式中的这一点或之前的不完整的结构化构造”(结果) )。

我要补充的是,我必须花点功夫来注释类型,因为由于某种我不知道的原因,编译器能够正确推断第一个列表,但对于第二个列表,类型始终被推断为单位另外,我的原始版本没有绑定名称结果,而是简单地“返回表达式”,如 in

if x <= xvalues.Head then 
    yvalues.Head

或 in

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:这是我的第一个问题:-)

I'm just learning f# so possibly I'm doing something very silly. Feel free to point me to the relevant documentation, I've searched but wasn't able to find. I am using Visual Studio 2010 beta on windows 7 (.Net 4.0).

Everything is going well with my first f# project. Well.. almost everything. In particular
I'm 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 am receiving a series of errors which completely elude my comprehension.

This is the list of errors and warnings:

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

  • "possible incorrect indentation: this token is offside of context started at position (39:10). Try indenting this token further or using standard formatting conventions " for the "if"

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

I will add that I had to sweat a bit to annotate the types, since for some reason unknown to me the compiler was able to infer correctly for the first list, but for the second the type was always inferred as unit Also, my original version didn't bind the name result, but simply "returned the expression", like in

if x <= xvalues.Head then 
    yvalues.Head

or in

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 leaves an error under the "for", saying that "This expression has type unit but is here used with type double" and that the "if" is possibly incorrectly indented.

I think that when I'll see the solution to this I'll feel silly, but I've been stuck on such a simple problem for more than an hour, so I am asking for your help.

Thanks in advance!

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

挽手叙旧 2024-08-08 22:35:19
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)
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)
思慕 2024-08-08 22:35:19

您的问题是,类似的东西

let result = yvalues.Head

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

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

Your problem is that something like

let result = yvalues.Head

is not a complete expression, and so it can't form the body of one of the branches of an if block. Your initial approach was correct, except that a for ... do loop doesn't return a meaningful value (it returns (), which is the only value of type unit, as the compiler is trying to explain; this is similar to void in languages like C#). Instead of the for loop, you'll want to use an expression that has the value you're looking for. The smallest change to your code would be to use a mutable value which you imperatively set in the loop. A more idiomatic approach would be to use a built in function like List.fold to condense the list to a single value. This is complicated by the fact that you need to access consecutive entries in your lists (and that you need to operate on both xvalues and yvalues simulataneously), which means you'd probably need to use List.zip and Seq.pairwise, which might reduce clarity for someone not used to F#.

Additionally, there are a few other changes you can apply to make your code more idiomatic. For instance, let x0 = xvalues.Item idx would more commonly be 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文