为什么 F# 中换行符的效果对于某些表达式不同,并且(可以说)在其中一些表达式中违反直觉?

Why is the effect of newlines in F# different for certain expressions, and (arguably) counter-intuitive in some of them?

Disclaimer/edit:这是一个相当简单的问题,但我问这个问题是因为我(仍然)经常对 F# 中的求值顺序感到困惑,尤其是。关于换行符与空格。反复试验总是让我到达我想去的地方,但我不认为如果你不得不诉诸反复试验,你就无法真正理解一种语言。

如果我写:

let res x =
    x * 1 = x
    |> ignore

一切都很好,但如果我写:

let res x =
    x * 1 = x && x * -1 = -x
    |> ignore

然后编译器抱怨(它说它期望 bool -> bool,而不是 bool -> unit)。我本来希望换行符在这里充当分隔符。

加括号有帮助,把它放在一行表明它被计算为(X && (Y |> Z)),其中XY是布尔表达式,Z是任意的函数。

这是真的吗?有没有更简单的方法来找出这一点?或者更好的是,空格什么时候是重要的运算符,什么时候不是?


再举个例子:

let v = x |> fun x -> float x |> fun y -> true

为什么y这里是float类型而不是int -> float类型?这可能是显而易见的,我肯定已经用这种方式编写了数千行代码,甚至感觉 自然,但为什么呢?

如果唯一的答案是"operator precedence and -> comes before |>",那就这样吧。但是我 guess/hope 虽然在这一切背后还有一些更学术或更正式的东西(而且我仍然觉得奇怪 && 的优先级低于 |>,同样,我不明白为什么和在那种情况下感觉违反直觉)。

https://docs.microsoft.com/en-us/dotnet/articles/fsharp/language-reference/symbol-and-operator-reference/#operator-precedence似乎&&的优先级高于|>所以你的猜测是正确的,你需要添加括号:

let res x =
  (x * 1 = x && x * -1 = -x)
  |> ignore

看起来新行不能作为分隔符,除非它有 let 绑定或符合列出的规则之一 here

例如,如果您采用以下表达式:

let res = 
  5 + 1
    .GetType()

你也会得到一个错误,因为它将 . 运算符应用于 1 而不是整个表达式,所以优先规则仍然有效,无论换行符如何。